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
17140M: Peter Zijlstra <peterz@infradead.org>17140M: Peter Zijlstra <peterz@infradead.org>
17141M: Ingo Molnar <mingo@redhat.com>17141M: Ingo Molnar <mingo@redhat.com>
17142M: Arnaldo Carvalho de Melo <acme@kernel.org>17142M: Arnaldo Carvalho de Melo <acme@kernel.org>
17143M: Namhyung Kim <namhyung@kernel.org>
17143R: Mark Rutland <mark.rutland@arm.com>17144R: Mark Rutland <mark.rutland@arm.com>
17144R: Alexander Shishkin <alexander.shishkin@linux.intel.com>17145R: Alexander Shishkin <alexander.shishkin@linux.intel.com>
17145R: Jiri Olsa <jolsa@kernel.org>17146R: Jiri Olsa <jolsa@kernel.org>
17146R: Namhyung Kim <namhyung@kernel.org>
17147R: Ian Rogers <irogers@google.com>17147R: Ian Rogers <irogers@google.com>
17148R: Adrian Hunter <adrian.hunter@intel.com>17148R: Adrian Hunter <adrian.hunter@intel.com>
17149L: linux-perf-users@vger.kernel.org17149L: linux-perf-users@vger.kernel.org
tools/build/Makefile.feature+1−0
@@ -32,6 +32,7 @@ FEATURE_TESTS_BASIC := \ · 31 unmodified lines
32 backtrace \32 backtrace \
33 dwarf \33 dwarf \
34 dwarf_getlocations \34 dwarf_getlocations \
35 dwarf_getcfi \
35 eventfd \36 eventfd \
36 fortify-source \37 fortify-source \
37 get_current_dir_name \38 get_current_dir_name \
tools/build/feature/Makefile+4−0
@@ -7,6 +7,7 @@ FILES= \ · 6 unmodified lines
7 test-bionic.bin \7 test-bionic.bin \
8 test-dwarf.bin \8 test-dwarf.bin \
9 test-dwarf_getlocations.bin \9 test-dwarf_getlocations.bin \
10 test-dwarf_getcfi.bin \
10 test-eventfd.bin \11 test-eventfd.bin \
11 test-fortify-source.bin \12 test-fortify-source.bin \
12 test-get_current_dir_name.bin \13 test-get_current_dir_name.bin \
@@ -154,6 +155,9 @@ $(OUTPUT)test-dwarf.bin: · 141 unmodified lines
154$(OUTPUT)test-dwarf_getlocations.bin:155$(OUTPUT)test-dwarf_getlocations.bin:
155 $(BUILD) $(DWARFLIBS)156 $(BUILD) $(DWARFLIBS)
156 157
158$(OUTPUT)test-dwarf_getcfi.bin:
159 $(BUILD) $(DWARFLIBS)
160
157$(OUTPUT)test-libelf-getphdrnum.bin:161$(OUTPUT)test-libelf-getphdrnum.bin:
158 $(BUILD) -lelf162 $(BUILD) -lelf
159 163
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
5int 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
4/*4/*
5 * Check OpenCSD library version is sufficient to provide required features5 * Check OpenCSD library version is sufficient to provide required features
6 */6 */
7#define OCSD_MIN_VER ((1 << 16) | (1 << 8) | (1))7#define OCSD_MIN_VER ((1 << 16) | (2 << 8) | (1))
8#if !defined(OCSD_VER_NUM) || (OCSD_VER_NUM < OCSD_MIN_VER)8#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"
10#endif10#endif
11 11
12int main(void)12int main(void)
tools/include/uapi/linux/perf_event.h+13−0
@@ -204,6 +204,8 @@ enum perf_branch_sample_type_shift { · 203 unmodified lines
204 204
205 PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */205 PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */
206 206
207 PERF_SAMPLE_BRANCH_COUNTERS_SHIFT = 19, /* save occurrences of events on a branch */
208
207 PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */209 PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
208};210};
209 211
@@ -235,6 +237,8 @@ enum perf_branch_sample_type { · 25 unmodified lines
235 237
236 PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT,238 PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT,
237 239
240 PERF_SAMPLE_BRANCH_COUNTERS = 1U << PERF_SAMPLE_BRANCH_COUNTERS_SHIFT,
241
238 PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,242 PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
239};243};
240 244
@@ -982,6 +986,12 @@ enum perf_event_type { · 741 unmodified lines
982 * { u64 nr;986 * { u64 nr;
983 * { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX987 * { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
984 * { u64 from, to, flags } lbr[nr];988 * { 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
985 * } && PERF_SAMPLE_BRANCH_STACK995 * } && PERF_SAMPLE_BRANCH_STACK
986 *996 *
987 * { u64 abi; # enum perf_sample_regs_abi997 * { u64 abi; # enum perf_sample_regs_abi
@@ -1427,6 +1437,9 @@ struct perf_branch_entry { · 439 unmodified lines
1427 reserved:31;1437 reserved:31;
1428};1438};
1429 1439
1440/* Size of used info bits in struct perf_branch_entry */
1441#define PERF_BRANCH_ENTRY_INFO_BITS_MAX 33
1442
1430union perf_sample_weight {1443union perf_sample_weight {
1431 __u64 full;1444 __u64 full;
1432#if defined(__LITTLE_ENDIAN_BITFIELD)1445#if defined(__LITTLE_ENDIAN_BITFIELD)
tools/lib/api/fs/fs.c+29−51
@@ -16,6 +16,7 @@ · 15 unmodified lines
16#include <sys/mount.h>16#include <sys/mount.h>
17 17
18#include "fs.h"18#include "fs.h"
19#include "../io.h"
19#include "debug-internal.h"20#include "debug-internal.h"
20 21
21#define _STR(x) #x22#define _STR(x) #x
@@ -344,53 +345,24 @@ int filename__read_ull(const char *filename, unsigned long long *value) · 322 unmodified lines
344 return filename__read_ull_base(filename, value, 0);345 return filename__read_ull_base(filename, value, 0);
345}346}
346 347
347#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */
348
349int filename__read_str(const char *filename, char **buf, size_t *sizep)348int filename__read_str(const char *filename, char **buf, size_t *sizep)
350{349{
351 size_t size = 0, alloc_size = 0;350 struct io io;
352 void *bf = NULL, *nbf;351 char bf[128];
353 int fd, n, err = 0;352 int err;
354 char sbuf[STRERR_BUFSIZE];
355 353
356 fd = open(filename, O_RDONLY);354 io.fd = open(filename, O_RDONLY);
357 if (fd < 0)355 if (io.fd < 0)
358 return -errno;356 return -errno;
359 357 io__init(&io, io.fd, bf, sizeof(bf));
360 do {358 *buf = NULL;
361 if (size == alloc_size) {359 err = io__getdelim(&io, buf, sizep, /*delim=*/-1);
362 alloc_size += BUFSIZ;360 if (err < 0) {
363 nbf = realloc(bf, alloc_size);361 free(*buf);
364 if (!nbf) {362 *buf = NULL;
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;
390 } else363 } else
391 free(bf);364 err = 0;
392 365 close(io.fd);
393 close(fd);
394 return err;366 return err;
395}367}
396 368
@@ -475,15 +447,22 @@ int sysfs__read_str(const char *entry, char **buf, size_t *sizep) · 78 unmodified lines
475 447
476int sysfs__read_bool(const char *entry, bool *value)448int sysfs__read_bool(const char *entry, bool *value)
477{449{
478 char *buf;450 struct io io;
479 size_t size;451 char bf[16];
480 int ret;452 int ret = 0;
453 char path[PATH_MAX];
454 const char *sysfs = sysfs__mountpoint();
455
456 if (!sysfs)
457 return -1;
481 458
482 ret = sysfs__read_str(entry, &buf, &size);459 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
483 if (ret < 0)460 io.fd = open(path, O_RDONLY);
484 return ret;461 if (io.fd < 0)
462 return -errno;
485 463
486 switch (buf[0]) {464 io__init(&io, io.fd, bf, sizeof(bf));
465 switch (io__get_char(&io)) {
487 case '1':466 case '1':
488 case 'y':467 case 'y':
489 case 'Y':468 case 'Y':
@@ -497,8 +476,7 @@ int sysfs__read_bool(const char *entry, bool *value) · 7 unmodified lines
497 default:476 default:
498 ret = -1;477 ret = -1;
499 }478 }
500 479 close(io.fd);
501 free(buf);
502 480
503 return ret;481 return ret;
504}482}
tools/lib/api/io.h+9−3
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <stdlib.h>12#include <stdlib.h>
13#include <string.h>13#include <string.h>
14#include <unistd.h>14#include <unistd.h>
15#include <linux/types.h>
15 16
16struct io {17struct io {
17 /* File descriptor being read/ */18 /* File descriptor being read/ */
@@ -140,8 +141,8 @@ static inline int io__get_dec(struct io *io, __u64 *dec) · 122 unmodified lines
140 }141 }
141}142}
142 143
143/* Read up to and including the first newline following the pattern of getline. */144/* Read up to and including the first delim. */
144static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out)145static inline ssize_t io__getdelim(struct io *io, char **line_out, size_t *line_len_out, int delim)
145{146{
146 char buf[128];147 char buf[128];
147 int buf_pos = 0;148 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
151 152
152 /* TODO: reuse previously allocated memory. */153 /* TODO: reuse previously allocated memory. */
153 free(*line_out);154 free(*line_out);
154 while (ch != '\n') {155 while (ch != delim) {
155 ch = io__get_char(io);156 ch = io__get_char(io);
156 157
157 if (ch < 0)158 if (ch < 0)
@@ -184,4 +185,9 @@ err_out: · 26 unmodified lines
184 return -ENOMEM;185 return -ENOMEM;
185}186}
186 187
188static 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
187#endif /* __API_IO__ */193#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
39 39
40 libperf_init(libperf_print);40 libperf_init(libperf_print);
41 41
42 cpus = perf_cpu_map__new(NULL);42 cpus = perf_cpu_map__new_online_cpus();
43 if (!cpus) {43 if (!cpus) {
44 fprintf(stderr, "failed to create cpus\n");44 fprintf(stderr, "failed to create cpus\n");
45 return -1;45 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
97 97
98[source,c]98[source,c]
99--99--
100 42 cpus = perf_cpu_map__new(NULL);100 42 cpus = perf_cpu_map__new_online_cpus();
101 43 if (!cpus) {101 43 if (!cpus) {
102 44 fprintf(stderr, "failed to create cpus\n");102 44 fprintf(stderr, "failed to create cpus\n");
103 45 return -1;103 45 return -1;
tools/lib/perf/Documentation/libperf.txt+2−2
@@ -37,7 +37,7 @@ SYNOPSIS · 36 unmodified lines
37 37
38 struct perf_cpu_map;38 struct perf_cpu_map;
39 39
40 struct perf_cpu_map *perf_cpu_map__dummy_new(void);40 struct perf_cpu_map *perf_cpu_map__new_any_cpu(void);
41 struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);41 struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
42 struct perf_cpu_map *perf_cpu_map__read(FILE *file);42 struct perf_cpu_map *perf_cpu_map__read(FILE *file);
43 struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);43 struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
@@ -46,7 +46,7 @@ SYNOPSIS · 2 unmodified lines
46 void perf_cpu_map__put(struct perf_cpu_map *map);46 void perf_cpu_map__put(struct perf_cpu_map *map);
47 int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);47 int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
48 int perf_cpu_map__nr(const struct perf_cpu_map *cpus);48 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);
50 int perf_cpu_map__max(struct perf_cpu_map *map);50 int perf_cpu_map__max(struct perf_cpu_map *map);
51 bool perf_cpu_map__has(const struct perf_cpu_map *map, int cpu);51 bool perf_cpu_map__has(const struct perf_cpu_map *map, int cpu);
52 52
tools/lib/perf/cpumap.c+38−27
@@ -9,6 +9,7 @@ · 8 unmodified lines
9#include <unistd.h>9#include <unistd.h>
10#include <ctype.h>10#include <ctype.h>
11#include <limits.h>11#include <limits.h>
12#include "internal.h"
12 13
13void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus)14void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus)
14{15{
@@ -27,7 +28,7 @@ struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus) · 12 unmodified lines
27 return result;28 return result;
28}29}
29 30
30struct perf_cpu_map *perf_cpu_map__dummy_new(void)31struct perf_cpu_map *perf_cpu_map__new_any_cpu(void)
31{32{
32 struct perf_cpu_map *cpus = perf_cpu_map__alloc(1);33 struct perf_cpu_map *cpus = perf_cpu_map__alloc(1);
33 34
@@ -66,15 +67,21 @@ void perf_cpu_map__put(struct perf_cpu_map *map) · 32 unmodified lines
66 }67 }
67}68}
68 69
69static struct perf_cpu_map *cpu_map__default_new(void)70static struct perf_cpu_map *cpu_map__new_sysconf(void)
70{71{
71 struct perf_cpu_map *cpus;72 struct perf_cpu_map *cpus;
72 int nr_cpus;73 int nr_cpus, nr_cpus_conf;
73 74
74 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);75 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
75 if (nr_cpus < 0)76 if (nr_cpus < 0)
76 return NULL;77 return NULL;
77 78
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
78 cpus = perf_cpu_map__alloc(nr_cpus);85 cpus = perf_cpu_map__alloc(nr_cpus);
79 if (cpus != NULL) {86 if (cpus != NULL) {
80 int i;87 int i;
@@ -86,9 +93,27 @@ static struct perf_cpu_map *cpu_map__default_new(void) · 5 unmodified lines
86 return cpus;93 return cpus;
87}94}
88 95
89struct perf_cpu_map *perf_cpu_map__default_new(void)96static struct perf_cpu_map *cpu_map__new_sysfs_online(void)
90{97{
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
109struct 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();
92}117}
93 118
94 119
@@ -180,27 +205,11 @@ struct perf_cpu_map *perf_cpu_map__read(FILE *file) · 85 unmodified lines
180 205
181 if (nr_cpus > 0)206 if (nr_cpus > 0)
182 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);207 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
183 else
184 cpus = cpu_map__default_new();
185out_free_tmp:208out_free_tmp:
186 free(tmp_cpus);209 free(tmp_cpus);
187 return cpus;210 return cpus;
188}211}
189 212
190static 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
204struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)213struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
205{214{
206 struct perf_cpu_map *cpus = NULL;215 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
211 int max_entries = 0;220 int max_entries = 0;
212 221
213 if (!cpu_list)222 if (!cpu_list)
214 return cpu_map__read_all_cpu_map();223 return perf_cpu_map__new_online_cpus();
215 224
216 /*225 /*
217 * must handle the case of empty cpumap to cover226 * 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
268 277
269 if (nr_cpus > 0)278 if (nr_cpus > 0)
270 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);279 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
271 else if (*cpu_list != '\0')280 else if (*cpu_list != '\0') {
272 cpus = cpu_map__default_new();281 pr_warning("Unexpected characters at end of cpu list ('%s'), using online CPUs.",
273 else282 cpu_list);
274 cpus = perf_cpu_map__dummy_new();283 cpus = perf_cpu_map__new_online_cpus();
284 } else
285 cpus = perf_cpu_map__new_any_cpu();
275invalid:286invalid:
276 free(tmp_cpus);287 free(tmp_cpus);
277out:288out:
@@ -300,7 +311,7 @@ int perf_cpu_map__nr(const struct perf_cpu_map *cpus) · 22 unmodified lines
300 return cpus ? __perf_cpu_map__nr(cpus) : 1;311 return cpus ? __perf_cpu_map__nr(cpus) : 1;
301}312}
302 313
303bool perf_cpu_map__empty(const struct perf_cpu_map *map)314bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map)
304{315{
305 return map ? __perf_cpu_map__cpu(map, 0).cpu == -1 : true;316 return map ? __perf_cpu_map__cpu(map, 0).cpu == -1 : true;
306}317}
tools/lib/perf/evlist.c+3−3
@@ -39,7 +39,7 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, · 38 unmodified lines
39 if (evsel->system_wide) {39 if (evsel->system_wide) {
40 /* System wide: set the cpu map of the evsel to all online CPUs. */40 /* System wide: set the cpu map of the evsel to all online CPUs. */
41 perf_cpu_map__put(evsel->cpus);41 perf_cpu_map__put(evsel->cpus);
42 evsel->cpus = perf_cpu_map__new(NULL);42 evsel->cpus = perf_cpu_map__new_online_cpus();
43 } else if (evlist->has_user_cpus && evsel->is_pmu_core) {43 } else if (evlist->has_user_cpus && evsel->is_pmu_core) {
44 /*44 /*
45 * User requested CPUs on a core PMU, ensure the requested CPUs45 * 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
619 619
620 /* One for each CPU */620 /* One for each CPU */
621 nr_mmaps = perf_cpu_map__nr(evlist->all_cpus);621 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)) {
623 /* Plus one for each thread */623 /* Plus one for each thread */
624 nr_mmaps += perf_thread_map__nr(evlist->threads);624 nr_mmaps += perf_thread_map__nr(evlist->threads);
625 /* Minus the per-thread CPU (-1) */625 /* Minus the per-thread CPU (-1) */
@@ -653,7 +653,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist, · 27 unmodified lines
653 if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)653 if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
654 return -ENOMEM;654 return -ENOMEM;
655 655
656 if (perf_cpu_map__empty(cpus))656 if (perf_cpu_map__has_any_cpu_or_is_empty(cpus))
657 return mmap_per_thread(evlist, ops, mp);657 return mmap_per_thread(evlist, ops, mp);
658 658
659 return mmap_per_cpu(evlist, ops, mp);659 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
120 static struct perf_cpu_map *empty_cpu_map;120 static struct perf_cpu_map *empty_cpu_map;
121 121
122 if (empty_cpu_map == NULL) {122 if (empty_cpu_map == NULL) {
123 empty_cpu_map = perf_cpu_map__dummy_new();123 empty_cpu_map = perf_cpu_map__new_any_cpu();
124 if (empty_cpu_map == NULL)124 if (empty_cpu_map == NULL)
125 return -ENOMEM;125 return -ENOMEM;
126 }126 }
tools/lib/perf/include/internal/mmap.h+2−1
@@ -33,7 +33,8 @@ struct perf_mmap { · 32 unmodified lines
33 bool overwrite;33 bool overwrite;
34 u64 flush;34 u64 flush;
35 libperf_unmap_cb_t unmap_cb;35 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;
37 struct perf_mmap *next;38 struct perf_mmap *next;
38};39};
39 40
tools/lib/perf/include/perf/cpumap.h+35−5
@@ -19,10 +19,23 @@ struct perf_cache { · 18 unmodified lines
19struct perf_cpu_map;19struct perf_cpu_map;
20 20
21/**21/**
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 */
24LIBPERF_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 */
33LIBPERF_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.
23 */38 */
24LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
25LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
26LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);39LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
27LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);40LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
28LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);41LIBPERF_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
31LIBPERF_API struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,44LIBPERF_API struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
32 struct perf_cpu_map *other);45 struct perf_cpu_map *other);
33LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);46LIBPERF_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 */
34LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);51LIBPERF_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 */
35LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);59LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
36/**60/**
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.
38 */62 */
39LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map);63LIBPERF_API bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map);
40LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map);64LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map);
41LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);65LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);
42LIBPERF_API bool perf_cpu_map__equal(const struct perf_cpu_map *lhs,66LIBPERF_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
51 (idx) < perf_cpu_map__nr(cpus); \75 (idx) < perf_cpu_map__nr(cpus); \
52 (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx))76 (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx))
53 77
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
54#define perf_cpu_map__for_each_idx(idx, cpus) \84#define perf_cpu_map__for_each_idx(idx, cpus) \
55 for ((idx) = 0; (idx) < perf_cpu_map__nr(cpus); (idx)++)85 for ((idx) = 0; (idx) < perf_cpu_map__nr(cpus); (idx)++)
56 86
tools/lib/perf/libperf.map+3−3
@@ -1,15 +1,15 @@
1LIBPERF_0.0.1 {1LIBPERF_0.0.1 {
2 global:2 global:
3 libperf_init;3 libperf_init;
4 perf_cpu_map__dummy_new;4 perf_cpu_map__new_any_cpu;
5 perf_cpu_map__default_new;5 perf_cpu_map__new_online_cpus;
6 perf_cpu_map__get;6 perf_cpu_map__get;
7 perf_cpu_map__put;7 perf_cpu_map__put;
8 perf_cpu_map__new;8 perf_cpu_map__new;
9 perf_cpu_map__read;9 perf_cpu_map__read;
10 perf_cpu_map__nr;10 perf_cpu_map__nr;
11 perf_cpu_map__cpu;11 perf_cpu_map__cpu;
12 perf_cpu_map__empty;12 perf_cpu_map__has_any_cpu_or_is_empty;
13 perf_cpu_map__max;13 perf_cpu_map__max;
14 perf_cpu_map__has;14 perf_cpu_map__has;
15 perf_thread_map__new_array;15 perf_thread_map__new_array;
tools/lib/perf/mmap.c+17−3
@@ -19,6 +19,7 @@ · 18 unmodified lines
19void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,19void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
20 bool overwrite, libperf_unmap_cb_t unmap_cb)20 bool overwrite, libperf_unmap_cb_t unmap_cb)
21{21{
22 /* Assume fields were zero initialized. */
22 map->fd = -1;23 map->fd = -1;
23 map->overwrite = overwrite;24 map->overwrite = overwrite;
24 map->unmap_cb = unmap_cb;25 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
51 52
52void perf_mmap__munmap(struct perf_mmap *map)53void perf_mmap__munmap(struct perf_mmap *map)
53{54{
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) {
55 munmap(map->base, perf_mmap__mmap_len(map));61 munmap(map->base, perf_mmap__mmap_len(map));
56 map->base = NULL;62 map->base = NULL;
57 map->fd = -1;63 map->fd = -1;
58 refcount_set(&map->refcnt, 0);64 refcount_set(&map->refcnt, 0);
59 }65 }
60 if (map && map->unmap_cb)66 if (map->unmap_cb)
61 map->unmap_cb(map);67 map->unmap_cb(map);
62}68}
63 69
@@ -223,9 +229,17 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map, · 159 unmodified lines
223 */229 */
224 if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) {230 if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) {
225 unsigned int offset = *startp;231 unsigned int offset = *startp;
226 unsigned int len = min(sizeof(*event), size), cpy;232 unsigned int len = size, cpy;
227 void *dst = map->event_copy;233 void *dst = map->event_copy;
228 234
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
229 do {243 do {
230 cpy = min(map->mask + 1 - (offset & map->mask), len);244 cpy = min(map->mask + 1 - (offset & map->mask), len);
231 memcpy(dst, &data[offset & map->mask], cpy);245 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
21 21
22 libperf_init(libperf_print);22 libperf_init(libperf_print);
23 23
24 cpus = perf_cpu_map__dummy_new();24 cpus = perf_cpu_map__new_any_cpu();
25 if (!cpus)25 if (!cpus)
26 return -1;26 return -1;
27 27
@@ -29,7 +29,7 @@ int test_cpumap(int argc, char **argv) · 1 unmodified line
29 perf_cpu_map__put(cpus);29 perf_cpu_map__put(cpus);
30 perf_cpu_map__put(cpus);30 perf_cpu_map__put(cpus);
31 31
32 cpus = perf_cpu_map__default_new();32 cpus = perf_cpu_map__new_online_cpus();
33 if (!cpus)33 if (!cpus)
34 return -1;34 return -1;
35 35
tools/lib/perf/tests/test-evlist.c+3−3
@@ -46,7 +46,7 @@ static int test_stat_cpu(void) · 45 unmodified lines
46 };46 };
47 int err, idx;47 int err, idx;
48 48
49 cpus = perf_cpu_map__new(NULL);49 cpus = perf_cpu_map__new_online_cpus();
50 __T("failed to create cpus", cpus);50 __T("failed to create cpus", cpus);
51 51
52 evlist = perf_evlist__new();52 evlist = perf_evlist__new();
@@ -261,7 +261,7 @@ static int test_mmap_thread(void) · 208 unmodified lines
261 threads = perf_thread_map__new_dummy();261 threads = perf_thread_map__new_dummy();
262 __T("failed to create threads", threads);262 __T("failed to create threads", threads);
263 263
264 cpus = perf_cpu_map__dummy_new();264 cpus = perf_cpu_map__new_any_cpu();
265 __T("failed to create cpus", cpus);265 __T("failed to create cpus", cpus);
266 266
267 perf_thread_map__set_pid(threads, 0, pid);267 perf_thread_map__set_pid(threads, 0, pid);
@@ -350,7 +350,7 @@ static int test_mmap_cpus(void) · 82 unmodified lines
350 350
351 attr.config = id;351 attr.config = id;
352 352
353 cpus = perf_cpu_map__new(NULL);353 cpus = perf_cpu_map__new_online_cpus();
354 __T("failed to create cpus", cpus);354 __T("failed to create cpus", cpus);
355 355
356 evlist = perf_evlist__new();356 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
27 };27 };
28 int err, idx;28 int err, idx;
29 29
30 cpus = perf_cpu_map__new(NULL);30 cpus = perf_cpu_map__new_online_cpus();
31 __T("failed to create cpus", cpus);31 __T("failed to create cpus", cpus);
32 32
33 evsel = perf_evsel__new(&attr);33 evsel = perf_evsel__new(&attr);
tools/lib/subcmd/help.c+14−4
@@ -52,11 +52,21 @@ void uniq(struct cmdnames *cmds) · 51 unmodified lines
52 if (!cmds->cnt)52 if (!cmds->cnt)
53 return;53 return;
54 54
55 for (i = j = 1; i < cmds->cnt; i++)55 for (i = 1; i < cmds->cnt; i++) {
56 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))56 if (!strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
57 cmds->names[j++] = cmds->names[i];57 zfree(&cmds->names[i - 1]);
58 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 }
59 cmds->cnt = j;67 cmds->cnt = j;
68 while (j < i)
69 cmds->names[j++] = NULL;
60}70}
61 71
62void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)72void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
tools/perf/.gitignore+4−0
@@ -39,6 +39,9 @@ trace/beauty/generated/ · 38 unmodified lines
39pmu-events/pmu-events.c39pmu-events/pmu-events.c
40pmu-events/jevents40pmu-events/jevents
41pmu-events/metric_test.log41pmu-events/metric_test.log
42tests/shell/*.shellcheck_log
43tests/shell/coresight/*.shellcheck_log
44tests/shell/lib/*.shellcheck_log
42feature/45feature/
43libapi/46libapi/
44libbpf/47libbpf/
@@ -49,3 +52,4 @@ libtraceevent/ · 4 unmodified lines
49libtraceevent_plugins/52libtraceevent_plugins/
50fixdep53fixdep
51Documentation/doc.dep54Documentation/doc.dep
55python_ext_build/
tools/perf/Documentation/itrace.txt+1−0
@@ -25,6 +25,7 @@ · 24 unmodified lines
25 q quicker (less detailed) decoding25 q quicker (less detailed) decoding
26 A approximate IPC26 A approximate IPC
27 Z prefer to ignore timestamps (so-called "timeless" decoding)27 Z prefer to ignore timestamps (so-called "timeless" decoding)
28 T use the timestamp trace as kernel time
28 29
29 The default is all events i.e. the same as --itrace=iybxwpe,30 The default is all events i.e. the same as --itrace=iybxwpe,
30 except for perf script where it is --itrace=ce31 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
155 stdio or stdio2 (Default: 0). Note that this is about selection of155 stdio or stdio2 (Default: 0). Note that this is about selection of
156 functions to display, not about lines within the function.156 functions to display, not about lines within the function.
157 157
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
158SEE ALSO169SEE ALSO
159--------170--------
160linkperf:perf-record[1], linkperf:perf-report[1]171linkperf:perf-record[1], linkperf:perf-report[1]
tools/perf/Documentation/perf-config.txt+2−2
@@ -251,7 +251,8 @@ annotate.*:: · 250 unmodified lines
251 addr2line binary to use for file names and line numbers.251 addr2line binary to use for file names and line numbers.
252 252
253 annotate.objdump::253 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.
255 256
256 annotate.disassembler_style::257 annotate.disassembler_style::
257 Use this to change the default disassembler style to some other value258 Use this to change the default disassembler style to some other value
@@ -722,7 +723,6 @@ session-<NAME>.*:: · 464 unmodified lines
722 Defines new record session for daemon. The value is record's723 Defines new record session for daemon. The value is record's
723 command line without the 'record' keyword.724 command line without the 'record' keyword.
724 725
725
726SEE ALSO726SEE ALSO
727--------727--------
728linkperf:perf[1]728linkperf: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
81which supports up to precise-level 2, and precise level 3 for81which supports up to precise-level 2, and precise level 3 for
82some special cases82some special cases
83 83
84On AMD systems it is implemented using IBS (up to precise-level 2).84On AMD systems it is implemented using IBS OP (up to precise-level 2).
85The precise modifier works with event types 0x76 (cpu-cycles, CPU85Unlike Intel PEBS which provides levels of precision, AMD core pmu is
86clocks not halted) and 0xC1 (micro-ops retired). Both events map to86inherently non-precise and IBS is inherently precise. (i.e. ibs_op//,
87IBS execution sampling (IBS op) with the IBS Op Counter Control bit87ibs_op//p, ibs_op//pp and ibs_op//ppp are all same). The precise modifier
88(IbsOpCntCtl) set respectively (see the88works 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)
90with the IBS Op Counter Control bit (IbsOpCntCtl) set respectively (see the
89Core Complex (CCX) -> Processor x86 Core -> Instruction Based Sampling (IBS)91Core Complex (CCX) -> Processor x86 Core -> Instruction Based Sampling (IBS)
90section of the [AMD Processor Programming Reference (PPR)] relevant to the92section of the [AMD Processor Programming Reference (PPR)] relevant to the
91family, model and stepping of the processor being used).93family, 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
119 119
120 120
121CONTENTION OPTIONS121CONTENTION OPTIONS
122--------------122------------------
123 123
124-k::124-k::
125--key=<value>::125--key=<value>::
tools/perf/Documentation/perf-record.txt+4−0
@@ -445,6 +445,10 @@ following filters are defined: · 444 unmodified lines
445 4th-Gen Xeon+ server), the save branch type is unconditionally enabled445 4th-Gen Xeon+ server), the save branch type is unconditionally enabled
446 when the taken branch stack sampling is enabled.446 when the taken branch stack sampling is enabled.
447 - priv: save privilege state during sampling in case binary is not available later447 - 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.
448 452
449+453+
450The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.454The 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
118 - retire_lat: On X86, this reports pipeline stall of this instruction compared118 - retire_lat: On X86, this reports pipeline stall of this instruction compared
119 to the previous instruction in cycles. And currently supported only on X86119 to the previous instruction in cycles. And currently supported only on X86
120 - simd: Flags describing a SIMD operation. "e" for empty Arm SVE predicate. "p" for partial Arm SVE predicate120 - 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.
121 124
122 By default, comm, dso and symbol keys are used.125 By default, comm, dso and symbol keys are used.
123 (i.e. --sort comm,dso,symbol)126 (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
422 422
423-A::423-A::
424--no-aggr::424--no-aggr::
425Do not aggregate counts across all monitored CPUs.425--no-merge::
426Do not aggregate/merge counts across monitored CPUs or PMUs.
427
428When multiple events are created from a single event specification,
429stat will, by default, aggregate the event counts and show the result
430in a single row. This option disables that behavior and shows the
431individual events and counts.
432
433Multiple events are created from a single event specification when:
434
4351. 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
4392. 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
4453. Aliases, which are listed immediately after the Kernel PMU events
446 by perf list, are used.
447
448--hybrid-merge::
449Merge core event counts from all core PMUs. In hybrid or big.LITTLE
450systems by default each core PMU will report its count
451separately. This option forces core PMU counts to be combined to give
452a behavior closer to having a single CPU type in the system.
426 453
427--topdown::454--topdown::
428Print top-down metrics supported by the CPU. This allows to determine455Print 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
475 502
476Error out if the input is higher than the supported max level.503Error out if the input is higher than the supported max level.
477 504
478--no-merge::
479Do not merge results from same PMUs.
480
481When multiple events are created from a single event specification,
482stat will, by default, aggregate the event counts and show the result
483in a single row. This option disables that behavior and shows
484the individual events and counts.
485
486Multiple events are created from a single event specification when:
4871. Prefix or glob matching is used for the PMU name.
4882. Aliases, which are listed immediately after the Kernel PMU events
489 by perf list, are used.
490
491--hybrid-merge::
492Merge the hybrid event counts from all PMUs.
493
494For hybrid events, by default, the stat aggregates and reports the event
495counts per PMU. But sometimes, it's also useful to aggregate event counts
496from all PMUs. This option enables that behavior and reports the counts
497without PMUs.
498
499For non-hybrid events, it should be no effect.
500
501--smi-cost::505--smi-cost::
502Measure SMI cost if msr/aperf/ and msr/smi/ events are supported.506Measure SMI cost if msr/aperf/ and msr/smi/ events are supported.
503 507
tools/perf/Documentation/perf.txt+3−0
@@ -64,6 +64,9 @@ OPTIONS · 63 unmodified lines
64 perf-event-open - Print perf_event_open() arguments and64 perf-event-open - Print perf_event_open() arguments and
65 return value65 return value
66 66
67--debug-file::
68 Write debug output to a specified file.
69
67DESCRIPTION70DESCRIPTION
68-----------71-----------
69Performance counters for Linux are a new kernel-based subsystem72Performance counters for Linux are a new kernel-based subsystem
tools/perf/Makefile.config+9−4
@@ -476,6 +476,11 @@ else · 475 unmodified lines
476 else476 else
477 CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT477 CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT
478 endif # dwarf_getlocations478 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
479 endif # Dwarf support484 endif # Dwarf support
480 endif # libelf support485 endif # libelf support
481endif # NO_LIBELF486endif # NO_LIBELF
@@ -680,15 +685,15 @@ ifndef BUILD_BPF_SKEL · 198 unmodified lines
680endif685endif
681 686
682ifeq ($(BUILD_BPF_SKEL),1)687ifeq ($(BUILD_BPF_SKEL),1)
683 ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),)688 ifeq ($(filter -DHAVE_LIBELF_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)),)
687 dummy := $(warning Warning: Disabled BPF skeletons as libelf is required by bpftool)689 dummy := $(warning Warning: Disabled BPF skeletons as libelf is required by bpftool)
688 BUILD_BPF_SKEL := 0690 BUILD_BPF_SKEL := 0
689 else ifeq ($(filter -DHAVE_ZLIB_SUPPORT, $(CFLAGS)),)691 else ifeq ($(filter -DHAVE_ZLIB_SUPPORT, $(CFLAGS)),)
690 dummy := $(warning Warning: Disabled BPF skeletons as zlib is required by bpftool)692 dummy := $(warning Warning: Disabled BPF skeletons as zlib is required by bpftool)
691 BUILD_BPF_SKEL := 0693 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
692 else ifeq ($(call get-executable,$(CLANG)),)697 else ifeq ($(call get-executable,$(CLANG)),)
693 dummy := $(warning Warning: Disabled BPF skeletons as clang ($(CLANG)) is missing)698 dummy := $(warning Warning: Disabled BPF skeletons as clang ($(CLANG)) is missing)
694 BUILD_BPF_SKEL := 0699 BUILD_BPF_SKEL := 0
tools/perf/Makefile.perf+11−2
@@ -134,6 +134,8 @@ include ../scripts/utilities.mak · 133 unmodified lines
134# x86 instruction decoder - new instructions test134# x86 instruction decoder - new instructions test
135#135#
136# Define GEN_VMLINUX_H to generate vmlinux.h from the BTF.136# 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
137 139
138# As per kernel Makefile, avoid funny character set dependencies140# As per kernel Makefile, avoid funny character set dependencies
139unexport LC_ALL141unexport LC_ALL
@@ -227,8 +229,15 @@ else · 87 unmodified lines
227 force_fixdep := $(config)229 force_fixdep := $(config)
228endif230endif
229 231
232# Runs shellcheck on perf test shell scripts
233ifeq ($(NO_SHELLCHECK),1)
234 SHELLCHECK :=
235else
236 SHELLCHECK := $(shell which shellcheck 2> /dev/null)
237endif
238
230export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK239export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK
231export HOSTCC HOSTLD HOSTAR HOSTCFLAGS240export HOSTCC HOSTLD HOSTAR HOSTCFLAGS SHELLCHECK
232 241
233include $(srctree)/tools/build/Makefile.include242include $(srctree)/tools/build/Makefile.include
234 243
@@ -1152,7 +1161,7 @@ bpf-skel-clean: · 917 unmodified lines
1152 1161
1153clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean tests-coresight-targets-clean1162clean:: $(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
1154 $(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-iostat $(LANG_BINDINGS)1163 $(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' -delete1164 $(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete -o -name '*.shellcheck_log' -delete
1156 $(Q)$(RM) $(OUTPUT).config-detected1165 $(Q)$(RM) $(OUTPUT).config-detected
1157 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so1166 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so
1158 $(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* \1167 $(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
199{199{
200 int i, err = -EINVAL;200 int i, err = -EINVAL;
201 struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus;201 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();
203 203
204 /* Set option of each CPU we have */204 /* Set option of each CPU we have */
205 for (i = 0; i < cpu__max_cpu().cpu; i++) {205 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
211 * program can run on any CPUs in this case, thus don't skip211 * program can run on any CPUs in this case, thus don't skip
212 * validation.212 * validation.
213 */213 */
214 if (!perf_cpu_map__empty(event_cpus) &&214 if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus) &&
215 !perf_cpu_map__has(event_cpus, cpu))215 !perf_cpu_map__has(event_cpus, cpu))
216 continue;216 continue;
217 217
@@ -435,7 +435,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, · 217 unmodified lines
435 * Also the case of per-cpu mmaps, need the contextID in order to be notified435 * Also the case of per-cpu mmaps, need the contextID in order to be notified
436 * when a context switch happened.436 * when a context switch happened.
437 */437 */
438 if (!perf_cpu_map__empty(cpus)) {438 if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
439 evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,439 evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
440 "timestamp", 1);440 "timestamp", 1);
441 evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,441 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
461 evsel->core.attr.sample_period = 1;461 evsel->core.attr.sample_period = 1;
462 462
463 /* In per-cpu case, always need the time of mmap events etc */463 /* 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))
465 evsel__set_sample_bit(evsel, TIME);465 evsel__set_sample_bit(evsel, TIME);
466 466
467 err = cs_etm_validate_config(itr, cs_etm_evsel);467 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
536 int i;536 int i;
537 int etmv3 = 0, etmv4 = 0, ete = 0;537 int etmv3 = 0, etmv4 = 0, ete = 0;
538 struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus;538 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();
540 540
541 /* cpu map is not empty, we have specific CPUs to work with */541 /* 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)) {
543 for (i = 0; i < cpu__max_cpu().cpu; i++) {543 for (i = 0; i < cpu__max_cpu().cpu; i++) {
544 struct perf_cpu cpu = { .cpu = i, };544 struct perf_cpu cpu = { .cpu = i, };
545 545
@@ -802,7 +802,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, · 256 unmodified lines
802 u64 nr_cpu, type;802 u64 nr_cpu, type;
803 struct perf_cpu_map *cpu_map;803 struct perf_cpu_map *cpu_map;
804 struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus;804 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();
806 struct cs_etm_recording *ptr =806 struct cs_etm_recording *ptr =
807 container_of(itr, struct cs_etm_recording, itr);807 container_of(itr, struct cs_etm_recording, itr);
808 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;808 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
814 return -EINVAL;814 return -EINVAL;
815 815
816 /* If the cpu_map is empty all online CPUs are involved */816 /* 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)) {
818 cpu_map = online_cpus;818 cpu_map = online_cpus;
819 } else {819 } else {
820 /* Make sure all specified CPUs are online */820 /* 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
232 * In the case of per-cpu mmaps, sample CPU for AUX event;232 * In the case of per-cpu mmaps, sample CPU for AUX event;
233 * also enable the timestamp tracing for samples correlation.233 * also enable the timestamp tracing for samples correlation.
234 */234 */
235 if (!perf_cpu_map__empty(cpus)) {235 if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
236 evsel__set_sample_bit(arm_spe_evsel, CPU);236 evsel__set_sample_bit(arm_spe_evsel, CPU);
237 evsel__set_config_if_unset(arm_spe_pmu, arm_spe_evsel,237 evsel__set_config_if_unset(arm_spe_pmu, arm_spe_evsel,
238 "ts_enable", 1);238 "ts_enable", 1);
@@ -265,7 +265,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, · 26 unmodified lines
265 tracking_evsel->core.attr.sample_period = 1;265 tracking_evsel->core.attr.sample_period = 1;
266 266
267 /* In per-cpu case, always need the time of mmap events etc */267 /* 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)) {
269 evsel__set_sample_bit(tracking_evsel, TIME);269 evsel__set_sample_bit(tracking_evsel, TIME);
270 evsel__set_sample_bit(tracking_evsel, CPU);270 evsel__set_sample_bit(tracking_evsel, CPU);
271 271
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
57 57
58int get_cpuid(char *buf, size_t sz)58int get_cpuid(char *buf, size_t sz)
59{59{
60 struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);60 struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();
61 int ret;61 int ret;
62 62
63 if (!cpus)63 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
61 const char *c = strchr(ops->raw, '#');61 const char *c = strchr(ops->raw, '#');
62 u64 start, end;62 u64 start, end;
63 63
64 ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);64 ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char);
65 ops->raw_func_start = strchr(ops->raw, '<');65 ops->jump.raw_func_start = strchr(ops->raw, '<');
66 66
67 if (ops->raw_func_start && c > ops->raw_func_start)67 if (ops->jump.raw_func_start && c > ops->jump.raw_func_start)
68 c = NULL;68 c = NULL;
69 69
70 if (c++ != NULL)70 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
47 evsel = evsel__next(evsel);47 evsel = evsel__next(evsel);
48 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);48 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
49 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));49 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));
51 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));51 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
52 return TEST_OK;52 return TEST_OK;
53}53}
@@ -102,7 +102,7 @@ static int test__hybrid_group_modifier1(struct evlist *evlist) · 48 unmodified lines
102 evsel = evsel__next(evsel);102 evsel = evsel__next(evsel);
103 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);103 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
104 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));104 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));
106 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));106 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
107 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);107 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
108 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);108 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
163 return TEST_OK;163 return TEST_OK;
164}164}
165 165
166static 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
166struct evlist_test {184struct evlist_test {
167 const char *name;185 const char *name;
168 bool (*valid)(void);186 bool (*valid)(void);
@@ -171,27 +189,27 @@ struct evlist_test { · 2 unmodified lines
171 189
172static const struct evlist_test test__hybrid_events[] = {190static const struct evlist_test test__hybrid_events[] = {
173 {191 {
174 .name = "cpu_core/cpu-cycles/",192 .name = "cpu_core/cycles/",
175 .check = test__hybrid_hw_event_with_pmu,193 .check = test__hybrid_hw_event_with_pmu,
176 /* 0 */194 /* 0 */
177 },195 },
178 {196 {
179 .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}",197 .name = "{cpu_core/cycles/,cpu_core/branches/}",
180 .check = test__hybrid_hw_group_event,198 .check = test__hybrid_hw_group_event,
181 /* 1 */199 /* 1 */
182 },200 },
183 {201 {
184 .name = "{cpu-clock,cpu_core/cpu-cycles/}",202 .name = "{cpu-clock,cpu_core/cycles/}",
185 .check = test__hybrid_sw_hw_group_event,203 .check = test__hybrid_sw_hw_group_event,
186 /* 2 */204 /* 2 */
187 },205 },
188 {206 {
189 .name = "{cpu_core/cpu-cycles/,cpu-clock}",207 .name = "{cpu_core/cycles/,cpu-clock}",
190 .check = test__hybrid_hw_sw_group_event,208 .check = test__hybrid_hw_sw_group_event,
191 /* 3 */209 /* 3 */
192 },210 },
193 {211 {
194 .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}",212 .name = "{cpu_core/cycles/k,cpu_core/branches/u}",
195 .check = test__hybrid_group_modifier1,213 .check = test__hybrid_group_modifier1,
196 /* 4 */214 /* 4 */
197 },215 },
@@ -215,6 +233,11 @@ static const struct evlist_test test__hybrid_events[] = { · 17 unmodified lines
215 .check = test__hybrid_cache_event,233 .check = test__hybrid_cache_event,
216 /* 8 */234 /* 8 */
217 },235 },
236 {
237 .name = "{cpu_core/cycles/,cpu_core/cpu-cycles/}",
238 .check = test__hybrid_hw_group_event_2,
239 /* 9 */
240 },
218};241};
219 242
220static int test_event(const struct evlist_test *e)243static 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
113 return roff->offset;113 return roff->offset;
114 return -EINVAL;114 return -EINVAL;
115}115}
116
117struct dwarf_regs_idx {
118 const char *name;
119 int idx;
120};
121
122static 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
142int 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
14 14
15#if defined(__x86_64__)15#if defined(__x86_64__)
16 16
17int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,17struct perf_event__synthesize_extra_kmaps_cb_args {
18 perf_event__handler_t process,18 struct perf_tool *tool;
19 struct machine *machine)19 perf_event__handler_t process;
20 struct machine *machine;
21 union perf_event *event;
22};
23
24static int perf_event__synthesize_extra_kmaps_cb(struct map *map, void *data)
20{25{
21 int rc = 0;26 struct perf_event__synthesize_extra_kmaps_cb_args *args = data;
22 struct map_rb_node *pos;27 union perf_event *event = args->event;
23 struct maps *kmaps = machine__kernel_maps(machine);28 struct kmap *kmap;
24 union perf_event *event = zalloc(sizeof(event->mmap) +29 size_t size;
25 machine->id_hdr_size);
26 30
27 if (!event) {31 if (!__map__is_extra_kernel_map(map))
28 pr_debug("Not enough memory synthesizing mmap event "32 return 0;
29 "for extra kernel maps\n");
30 return -1;
31 }
32 33
33 maps__for_each_entry(kmaps, pos) {34 kmap = map__kmap(map);
34 struct kmap *kmap;
35 size_t size;
36 struct map *map = pos->map;
37 35
38 if (!__map__is_extra_kernel_map(map))36 size = sizeof(event->mmap) - sizeof(event->mmap.filename) +
39 continue;37 PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) +
38 args->machine->id_hdr_size;
40 39
41 kmap = map__kmap(map);40 memset(event, 0, size);
42 41
43 size = sizeof(event->mmap) - sizeof(event->mmap.filename) +42 event->mmap.header.type = PERF_RECORD_MMAP;
44 PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) +
45 machine->id_hdr_size;
46 43
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;
48 52
49 event->mmap.header.type = PERF_RECORD_MMAP;53 event->mmap.header.size = size;
50 54
51 /*55 event->mmap.start = map__start(map);
52 * kernel uses 0 for user space maps, see kernel/perf_event.c56 event->mmap.len = map__size(map);
53 * __perf_event_mmap57 event->mmap.pgoff = map__pgoff(map);
54 */58 event->mmap.pid = args->machine->pid;
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;
59 59
60 event->mmap.header.size = size;60 strlcpy(event->mmap.filename, kmap->name, PATH_MAX);
61 61
62 event->mmap.start = map__start(map);62 if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0)
63 event->mmap.len = map__size(map);63 return -1;
64 event->mmap.pgoff = map__pgoff(map);
65 event->mmap.pid = machine->pid;
66 64
67 strlcpy(event->mmap.filename, kmap->name, PATH_MAX);65 return 0;
66}
68 67
69 if (perf_tool__process_synth_event(tool, event, machine,68int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
70 process) != 0) {69 perf_event__handler_t process,
71 rc = -1;70 struct machine *machine)
72 break;71{
73 }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;
74 }85 }
75 86
76 free(event);87 rc = maps__for_each_map(kmaps, perf_event__synthesize_extra_kmaps_cb, &args);
88
89 free(args.event);
77 return rc;90 return rc;
78}91}
79 92
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
143 if (!opts->full_auxtrace)143 if (!opts->full_auxtrace)
144 return 0;144 return 0;
145 145
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)) {
147 pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n");147 pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n");
148 return -EINVAL;148 return -EINVAL;
149 }149 }
@@ -224,7 +224,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, · 74 unmodified lines
224 * In the case of per-cpu mmaps, we need the CPU on the224 * In the case of per-cpu mmaps, we need the CPU on the
225 * AUX event.225 * AUX event.
226 */226 */
227 if (!perf_cpu_map__empty(cpus))227 if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus))
228 evsel__set_sample_bit(intel_bts_evsel, CPU);228 evsel__set_sample_bit(intel_bts_evsel, CPU);
229 }229 }
230 230
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
369 ui__warning("Intel Processor Trace: TSC not available\n");369 ui__warning("Intel Processor Trace: TSC not available\n");
370 }370 }
371 371
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);
373 373
374 auxtrace_info->type = PERF_AUXTRACE_INTEL_PT;374 auxtrace_info->type = PERF_AUXTRACE_INTEL_PT;
375 auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type;375 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
774 * Per-cpu recording needs sched_switch events to distinguish different774 * Per-cpu recording needs sched_switch events to distinguish different
775 * threads.775 * threads.
776 */776 */
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) &&
778 !record_opts__no_switch_events(opts)) {778 !record_opts__no_switch_events(opts)) {
779 if (perf_can_record_switch_events()) {779 if (perf_can_record_switch_events()) {
780 bool cpu_wide = !target__none(&opts->target) &&780 bool cpu_wide = !target__none(&opts->target) &&
@@ -832,7 +832,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 51 unmodified lines
832 * In the case of per-cpu mmaps, we need the CPU on the832 * In the case of per-cpu mmaps, we need the CPU on the
833 * AUX event.833 * AUX event.
834 */834 */
835 if (!perf_cpu_map__empty(cpus))835 if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus))
836 evsel__set_sample_bit(intel_pt_evsel, CPU);836 evsel__set_sample_bit(intel_pt_evsel, CPU);
837 }837 }
838 838
@@ -858,7 +858,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 19 unmodified lines
858 tracking_evsel->immediate = true;858 tracking_evsel->immediate = true;
859 859
860 /* In per-cpu case, always need the time of mmap events etc */860 /* 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)) {
862 evsel__set_sample_bit(tracking_evsel, TIME);862 evsel__set_sample_bit(tracking_evsel, TIME);
863 /* And the CPU for switch events */863 /* And the CPU for switch events */
864 evsel__set_sample_bit(tracking_evsel, CPU);864 evsel__set_sample_bit(tracking_evsel, CPU);
@@ -870,7 +870,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 5 unmodified lines
870 * Warn the user when we do not have enough information to decode i.e.870 * Warn the user when we do not have enough information to decode i.e.
871 * per-cpu with no sched_switch (except workload-only).871 * per-cpu with no sched_switch (except workload-only).
872 */872 */
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) &&
874 !target__none(&opts->target) &&874 !target__none(&opts->target) &&
875 !intel_pt_evsel->core.attr.exclude_user)875 !intel_pt_evsel->core.attr.exclude_user)
876 ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n");876 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
330 act.sa_sigaction = toggle_done;330 act.sa_sigaction = toggle_done;
331 sigaction(SIGINT, &act, NULL);331 sigaction(SIGINT, &act, NULL);
332 332
333 cpu = perf_cpu_map__new(NULL);333 cpu = perf_cpu_map__new_online_cpus();
334 if (!cpu)334 if (!cpu)
335 goto errmem;335 goto errmem;
336 336
tools/perf/bench/epoll-wait.c+1−1
@@ -444,7 +444,7 @@ int bench_epoll_wait(int argc, const char **argv) · 443 unmodified lines
444 act.sa_sigaction = toggle_done;444 act.sa_sigaction = toggle_done;
445 sigaction(SIGINT, &act, NULL);445 sigaction(SIGINT, &act, NULL);
446 446
447 cpu = perf_cpu_map__new(NULL);447 cpu = perf_cpu_map__new_online_cpus();
448 if (!cpu)448 if (!cpu)
449 goto errmem;449 goto errmem;
450 450
tools/perf/bench/futex-hash.c+1−1
@@ -138,7 +138,7 @@ int bench_futex_hash(int argc, const char **argv) · 137 unmodified lines
138 exit(EXIT_FAILURE);138 exit(EXIT_FAILURE);
139 }139 }
140 140
141 cpu = perf_cpu_map__new(NULL);141 cpu = perf_cpu_map__new_online_cpus();
142 if (!cpu)142 if (!cpu)
143 goto errmem;143 goto errmem;
144 144
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
172 if (argc)172 if (argc)
173 goto err;173 goto err;
174 174
175 cpu = perf_cpu_map__new(NULL);175 cpu = perf_cpu_map__new_online_cpus();
176 if (!cpu)176 if (!cpu)
177 err(EXIT_FAILURE, "calloc");177 err(EXIT_FAILURE, "calloc");
178 178
tools/perf/bench/futex-requeue.c+1−1
@@ -174,7 +174,7 @@ int bench_futex_requeue(int argc, const char **argv) · 173 unmodified lines
174 if (argc)174 if (argc)
175 goto err;175 goto err;
176 176
177 cpu = perf_cpu_map__new(NULL);177 cpu = perf_cpu_map__new_online_cpus();
178 if (!cpu)178 if (!cpu)
179 err(EXIT_FAILURE, "cpu_map__new");179 err(EXIT_FAILURE, "cpu_map__new");
180 180
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
264 err(EXIT_FAILURE, "mlockall");264 err(EXIT_FAILURE, "mlockall");
265 }265 }
266 266
267 cpu = perf_cpu_map__new(NULL);267 cpu = perf_cpu_map__new_online_cpus();
268 if (!cpu)268 if (!cpu)
269 err(EXIT_FAILURE, "calloc");269 err(EXIT_FAILURE, "calloc");
270 270
tools/perf/bench/futex-wake.c+1−1
@@ -149,7 +149,7 @@ int bench_futex_wake(int argc, const char **argv) · 148 unmodified lines
149 exit(EXIT_FAILURE);149 exit(EXIT_FAILURE);
150 }150 }
151 151
152 cpu = perf_cpu_map__new(NULL);152 cpu = perf_cpu_map__new_online_cpus();
153 if (!cpu)153 if (!cpu)
154 err(EXIT_FAILURE, "calloc");154 err(EXIT_FAILURE, "calloc");
155 155
tools/perf/bench/sched-seccomp-notify.c+1−1
@@ -32,7 +32,7 @@ static bool sync_mode; · 31 unmodified lines
32static const struct option options[] = {32static const struct option options[] = {
33 OPT_U64('l', "loop", &loops, "Specify number of loops"),33 OPT_U64('l', "loop", &loops, "Specify number of loops"),
34 OPT_BOOLEAN('s', "sync-mode", &sync_mode,34 OPT_BOOLEAN('s', "sync-mode", &sync_mode,
35 "Enable the synchronious mode for seccomp notifications"),35 "Enable the synchronous mode for seccomp notifications"),
36 OPT_END()36 OPT_END()
37};37};
38 38
tools/perf/builtin-annotate.c+272−28
@@ -20,6 +20,7 @@ · 19 unmodified lines
20#include "util/evlist.h"20#include "util/evlist.h"
21#include "util/evsel.h"21#include "util/evsel.h"
22#include "util/annotate.h"22#include "util/annotate.h"
23#include "util/annotate-data.h"
23#include "util/event.h"24#include "util/event.h"
24#include <subcmd/parse-options.h>25#include <subcmd/parse-options.h>
25#include "util/parse-events.h"26#include "util/parse-events.h"
@@ -45,7 +46,6 @@ · 19 unmodified lines
45struct perf_annotate {46struct perf_annotate {
46 struct perf_tool tool;47 struct perf_tool tool;
47 struct perf_session *session;48 struct perf_session *session;
48 struct annotation_options opts;
49#ifdef HAVE_SLANG_SUPPORT49#ifdef HAVE_SLANG_SUPPORT
50 bool use_tui;50 bool use_tui;
51#endif51#endif
@@ -56,9 +56,13 @@ struct perf_annotate { · 4 unmodified lines
56 bool skip_missing;56 bool skip_missing;
57 bool has_br_stack;57 bool has_br_stack;
58 bool group_set;58 bool group_set;
59 bool data_type;
60 bool type_stat;
61 bool insn_stat;
59 float min_percent;62 float min_percent;
60 const char *sym_hist_filter;63 const char *sym_hist_filter;
61 const char *cpu_list;64 const char *cpu_list;
65 const char *target_data_type;
62 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);66 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
63};67};
64 68
@@ -94,6 +98,7 @@ static void process_basic_block(struct addr_map_symbol *start, · 29 unmodified lines
94 struct annotation *notes = sym ? symbol__annotation(sym) : NULL;98 struct annotation *notes = sym ? symbol__annotation(sym) : NULL;
95 struct block_range_iter iter;99 struct block_range_iter iter;
96 struct block_range *entry;100 struct block_range *entry;
101 struct annotated_branch *branch;
97 102
98 /*103 /*
99 * Sanity; NULL isn't executable and the CPU cannot execute backwards104 * 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
105 if (!block_range_iter__valid(&iter))110 if (!block_range_iter__valid(&iter))
106 return;111 return;
107 112
113 branch = annotation__get_branch(notes);
114
108 /*115 /*
109 * First block in range is a branch target.116 * First block in range is a branch target.
110 */117 */
@@ -118,8 +125,8 @@ static void process_basic_block(struct addr_map_symbol *start, · 7 unmodified lines
118 entry->coverage++;125 entry->coverage++;
119 entry->sym = sym;126 entry->sym = sym;
120 127
121 if (notes)128 if (branch)
122 notes->max_coverage = max(notes->max_coverage, entry->coverage);129 branch->max_coverage = max(branch->max_coverage, entry->coverage);
123 130
124 } while (block_range_iter__next(&iter));131 } while (block_range_iter__next(&iter));
125 132
@@ -315,9 +322,153 @@ static int hist_entry__tty_annotate(struct hist_entry *he, · 189 unmodified lines
315 struct perf_annotate *ann)322 struct perf_annotate *ann)
316{323{
317 if (!ann->use_stdio2)324 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
330static 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
360static 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);
319 371
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
401static 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
438static 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");
321}472}
322 473
323static void hists__find_annotations(struct hists *hists,474static void hists__find_annotations(struct hists *hists,
@@ -327,6 +478,11 @@ static void hists__find_annotations(struct hists *hists, · 3 unmodified lines
327 struct rb_node *nd = rb_first_cached(&hists->entries), *next;478 struct rb_node *nd = rb_first_cached(&hists->entries), *next;
328 int key = K_RIGHT;479 int key = K_RIGHT;
329 480
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
330 while (nd) {486 while (nd) {
331 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);487 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
332 struct annotation *notes;488 struct annotation *notes;
@@ -359,11 +515,38 @@ find_next: · 26 unmodified lines
359 continue;515 continue;
360 }516 }
361 517
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
362 if (use_browser == 2) {546 if (use_browser == 2) {
363 int ret;547 int ret;
364 int (*annotate)(struct hist_entry *he,548 int (*annotate)(struct hist_entry *he,
365 struct evsel *evsel,549 struct evsel *evsel,
366 struct annotation_options *options,
367 struct hist_browser_timer *hbt);550 struct hist_browser_timer *hbt);
368 551
369 annotate = dlsym(perf_gtk_handle,552 annotate = dlsym(perf_gtk_handle,
@@ -373,14 +556,14 @@ find_next: · 3 unmodified lines
373 return;556 return;
374 }557 }
375 558
376 ret = annotate(he, evsel, &ann->opts, NULL);559 ret = annotate(he, evsel, NULL);
377 if (!ret || !ann->skip_missing)560 if (!ret || !ann->skip_missing)
378 return;561 return;
379 562
380 /* skip missing symbols */563 /* skip missing symbols */
381 nd = rb_next(nd);564 nd = rb_next(nd);
382 } else if (use_browser == 1) {565 } 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);
384 567
385 switch (key) {568 switch (key) {
386 case -1:569 case -1:
@@ -422,9 +605,9 @@ static int __cmd_annotate(struct perf_annotate *ann) · 35 unmodified lines
422 goto out;605 goto out;
423 }606 }
424 607
425 if (!ann->opts.objdump_path) {608 if (!annotate_opts.objdump_path) {
426 ret = perf_env__lookup_objdump(&session->header.env,609 ret = perf_env__lookup_objdump(&session->header.env,
427 &ann->opts.objdump_path);610 &annotate_opts.objdump_path);
428 if (ret)611 if (ret)
429 goto out;612 goto out;
430 }613 }
@@ -457,8 +640,20 @@ static int __cmd_annotate(struct perf_annotate *ann) · 26 unmodified lines
457 evsel__reset_sample_bit(pos, CALLCHAIN);640 evsel__reset_sample_bit(pos, CALLCHAIN);
458 evsel__output_resort(pos, NULL);641 evsel__output_resort(pos, NULL);
459 642
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 }
461 continue;655 continue;
656 }
462 657
463 hists__find_annotations(hists, pos, ann);658 hists__find_annotations(hists, pos, ann);
464 }659 }
@@ -469,6 +664,20 @@ static int __cmd_annotate(struct perf_annotate *ann) · 4 unmodified lines
469 goto out;664 goto out;
470 }665 }
471 666
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
472 if (use_browser == 2) {681 if (use_browser == 2) {
473 void (*show_annotations)(void);682 void (*show_annotations)(void);
474 683
@@ -495,6 +704,17 @@ static int parse_percent_limit(const struct option *opt, const char *str, · 20 unmodified lines
495 return 0;704 return 0;
496}705}
497 706
707static 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
498static const char * const annotate_usage[] = {718static const char * const annotate_usage[] = {
499 "perf annotate [<options>]",719 "perf annotate [<options>]",
500 NULL720 NULL
@@ -558,9 +778,9 @@ int cmd_annotate(int argc, const char **argv) · 57 unmodified lines
558 "file", "vmlinux pathname"),778 "file", "vmlinux pathname"),
559 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,779 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
560 "load module symbols - WARNING: use only with -k and LIVE kernel"),780 "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,
562 "print matching source lines (may be slow)"),782 "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,
564 "Don't shorten the displayed pathnames"),784 "Don't shorten the displayed pathnames"),
565 OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,785 OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
566 "Skip symbols that cannot be annotated"),786 "Skip symbols that cannot be annotated"),
@@ -571,15 +791,15 @@ int cmd_annotate(int argc, const char **argv) · 4 unmodified lines
571 OPT_CALLBACK(0, "symfs", NULL, "directory",791 OPT_CALLBACK(0, "symfs", NULL, "directory",
572 "Look for files with symbols relative to this directory",792 "Look for files with symbols relative to this directory",
573 symbol__config_symfs),793 symbol__config_symfs),
574 OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src,794 OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src,
575 "Interleave source code with assembly code (default)"),795 "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,
577 "Display raw encoding of assembly instructions (default)"),797 "Display raw encoding of assembly instructions (default)"),
578 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",798 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
579 "Specify disassembler style (e.g. -M intel for intel syntax)"),799 "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",
581 "Add prefix to source file path names in programs (with --prefix-strip)"),801 "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",
583 "Strip first N entries of source file path name in programs (with --prefix)"),803 "Strip first N entries of source file path name in programs (with --prefix)"),
584 OPT_STRING(0, "objdump", &objdump_path, "path",804 OPT_STRING(0, "objdump", &objdump_path, "path",
585 "objdump binary to use for disassembly and annotations"),805 "objdump binary to use for disassembly and annotations"),
@@ -598,7 +818,7 @@ int cmd_annotate(int argc, const char **argv) · 12 unmodified lines
598 OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode",818 OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode",
599 "'always' (default), 'never' or 'auto' only applicable to --stdio mode",819 "'always' (default), 'never' or 'auto' only applicable to --stdio mode",
600 stdio__config_color, "always"),820 stdio__config_color, "always"),
601 OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period",821 OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period",
602 "Set percent type local/global-period/hits",822 "Set percent type local/global-period/hits",
603 annotate_parse_percent_type),823 annotate_parse_percent_type),
604 OPT_CALLBACK(0, "percent-limit", &annotate, "percent",824 OPT_CALLBACK(0, "percent-limit", &annotate, "percent",
@@ -606,7 +826,13 @@ int cmd_annotate(int argc, const char **argv) · 1 unmodified line
606 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",826 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
607 "Instruction Tracing options\n" ITRACE_HELP,827 "Instruction Tracing options\n" ITRACE_HELP,
608 itrace_parse_synth_opts),828 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"),
610 OPT_END()836 OPT_END()
611 };837 };
612 int ret;838 int ret;
@@ -614,13 +840,13 @@ int cmd_annotate(int argc, const char **argv) · 1 unmodified line
614 set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE);840 set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE);
615 set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE);841 set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE);
616 842
617 annotation_options__init(&annotate.opts);843 annotation_options__init();
618 844
619 ret = hists__init();845 ret = hists__init();
620 if (ret < 0)846 if (ret < 0)
621 return ret;847 return ret;
622 848
623 annotation_config__init(&annotate.opts);849 annotation_config__init();
624 850
625 argc = parse_options(argc, argv, options, annotate_usage, 0);851 argc = parse_options(argc, argv, options, annotate_usage, 0);
626 if (argc) {852 if (argc) {
@@ -635,13 +861,13 @@ int cmd_annotate(int argc, const char **argv) · 8 unmodified lines
635 }861 }
636 862
637 if (disassembler_style) {863 if (disassembler_style) {
638 annotate.opts.disassembler_style = strdup(disassembler_style);864 annotate_opts.disassembler_style = strdup(disassembler_style);
639 if (!annotate.opts.disassembler_style)865 if (!annotate_opts.disassembler_style)
640 return -ENOMEM;866 return -ENOMEM;
641 }867 }
642 if (objdump_path) {868 if (objdump_path) {
643 annotate.opts.objdump_path = strdup(objdump_path);869 annotate_opts.objdump_path = strdup(objdump_path);
644 if (!annotate.opts.objdump_path)870 if (!annotate_opts.objdump_path)
645 return -ENOMEM;871 return -ENOMEM;
646 }872 }
647 if (addr2line_path) {873 if (addr2line_path) {
@@ -650,7 +876,7 @@ int cmd_annotate(int argc, const char **argv) · 2 unmodified lines
650 return -ENOMEM;876 return -ENOMEM;
651 }877 }
652 878
653 if (annotate_check_args(&annotate.opts) < 0)879 if (annotate_check_args() < 0)
654 return -EINVAL;880 return -EINVAL;
655 881
656#ifdef HAVE_GTK2_SUPPORT882#ifdef HAVE_GTK2_SUPPORT
@@ -660,6 +886,13 @@ int cmd_annotate(int argc, const char **argv) · 3 unmodified lines
660 }886 }
661#endif887#endif
662 888
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
663 ret = symbol__validate_sym_arguments();896 ret = symbol__validate_sym_arguments();
664 if (ret)897 if (ret)
665 return ret;898 return ret;
@@ -702,6 +935,14 @@ int cmd_annotate(int argc, const char **argv) · 36 unmodified lines
702 use_browser = 2;935 use_browser = 2;
703#endif936#endif
704 937
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
705 setup_browser(true);946 setup_browser(true);
706 947
707 /*948 /*
@@ -709,7 +950,10 @@ int cmd_annotate(int argc, const char **argv) · 1 unmodified line
709 * symbol, we do not care about the processes in annotate,950 * symbol, we do not care about the processes in annotate,
710 * set sort order to avoid repeated output.951 * set sort order to avoid repeated output.
711 */952 */
712 sort_order = "dso,symbol";953 if (annotate.data_type)
954 sort_order = "dso,type";
955 else
956 sort_order = "dso,symbol";
713 957
714 /*958 /*
715 * Set SORT_MODE__BRANCH so that annotate display IPC/Cycle959 * Set SORT_MODE__BRANCH so that annotate display IPC/Cycle
@@ -731,7 +975,7 @@ out_delete: · 15 unmodified lines
731#ifndef NDEBUG975#ifndef NDEBUG
732 perf_session__delete(annotate.session);976 perf_session__delete(annotate.session);
733#endif977#endif
734 annotation_options__exit(&annotate.opts);978 annotation_options__exit();
735 979
736 return ret;980 return ret;
737}981}
tools/perf/builtin-c2c.c+1−1
@@ -2320,7 +2320,7 @@ static int setup_nodes(struct perf_session *session) · 2319 unmodified lines
2320 nodes[node] = set;2320 nodes[node] = set;
2321 2321
2322 /* empty node, skip */2322 /* empty node, skip */
2323 if (perf_cpu_map__empty(map))2323 if (perf_cpu_map__has_any_cpu_or_is_empty(map))
2324 continue;2324 continue;
2325 2325
2326 perf_cpu_map__for_each_cpu(cpu, idx, map) {2326 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
333 333
334static int reset_tracing_cpu(void)334static int reset_tracing_cpu(void)
335{335{
336 struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL);336 struct perf_cpu_map *cpumap = perf_cpu_map__new_online_cpus();
337 int ret;337 int ret;
338 338
339 ret = set_tracing_cpumask(cpumap);339 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
2265 "perf inject [<options>]",2265 "perf inject [<options>]",
2266 NULL2266 NULL
2267 };2267 };
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
2268#ifndef HAVE_JITDUMP2274#ifndef HAVE_JITDUMP
2269 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);2275 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
2270#endif2276#endif
tools/perf/builtin-lock.c+3−1
@@ -2285,8 +2285,10 @@ setup_args: · 2284 unmodified lines
2285 else2285 else
2286 ev_name = strdup(contention_tracepoints[j].name);2286 ev_name = strdup(contention_tracepoints[j].name);
2287 2287
2288 if (!ev_name)2288 if (!ev_name) {
2289 free(rec_argv);
2289 return -ENOMEM;2290 return -ENOMEM;
2291 }
2290 2292
2291 rec_argv[i++] = "-e";2293 rec_argv[i++] = "-e";
2292 rec_argv[i++] = ev_name;2294 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
270 270
271static int record__aio_enabled(struct record *rec);271static int record__aio_enabled(struct record *rec);
272static int record__comp_enabled(struct record *rec);272static int record__comp_enabled(struct record *rec);
273static size_t zstd_compress(struct perf_session *session, struct mmap *map,273static ssize_t zstd_compress(struct perf_session *session, struct mmap *map,
274 void *dst, size_t dst_size, void *src, size_t src_size);274 void *dst, size_t dst_size, void *src, size_t src_size);
275 275
276#ifdef HAVE_AIO_SUPPORT276#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
405 */405 */
406 406
407 if (record__comp_enabled(aio->rec)) {407 if (record__comp_enabled(aio->rec)) {
408 size = zstd_compress(aio->rec->session, NULL, aio->data + aio->size,408 ssize_t compressed = zstd_compress(aio->rec->session, NULL, aio->data + aio->size,
409 mmap__mmap_len(map) - aio->size,409 mmap__mmap_len(map) - aio->size,
410 buf, size);410 buf, size);
411 if (compressed < 0)
412 return (int)compressed;
413
414 size = compressed;
411 } else {415 } else {
412 memcpy(aio->data + aio->size, buf, size);416 memcpy(aio->data + aio->size, buf, size);
413 }417 }
@@ -633,7 +637,13 @@ static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size) · 219 unmodified lines
633 struct record *rec = to;637 struct record *rec = to;
634 638
635 if (record__comp_enabled(rec)) {639 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;
637 bf = map->data;647 bf = map->data;
638 }648 }
639 649
@@ -1350,7 +1360,7 @@ static int record__open(struct record *rec) · 710 unmodified lines
1350 evlist__for_each_entry(evlist, pos) {1360 evlist__for_each_entry(evlist, pos) {
1351try_again:1361try_again:
1352 if (evsel__open(pos, pos->core.cpus, pos->core.threads) < 0) {1362 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))) {
1354 if (verbose > 0)1364 if (verbose > 0)
1355 ui__warning("%s\n", msg);1365 ui__warning("%s\n", msg);
1356 goto try_again;1366 goto try_again;
@@ -1527,10 +1537,10 @@ static size_t process_comp_header(void *record, size_t increment) · 170 unmodified lines
1527 return size;1537 return size;
1528}1538}
1529 1539
1530static size_t zstd_compress(struct perf_session *session, struct mmap *map,1540static ssize_t zstd_compress(struct perf_session *session, struct mmap *map,
1531 void *dst, size_t dst_size, void *src, size_t src_size)1541 void *dst, size_t dst_size, void *src, size_t src_size)
1532{1542{
1533 size_t compressed;1543 ssize_t compressed;
1534 size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_record_compressed) - 1;1544 size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_record_compressed) - 1;
1535 struct zstd_data *zstd_data = &session->zstd_data;1545 struct zstd_data *zstd_data = &session->zstd_data;
1536 1546
@@ -1539,6 +1549,8 @@ static size_t zstd_compress(struct perf_session *session, struct mmap *map, · 2 unmodified lines
1539 1549
1540 compressed = zstd_compress_stream_to_records(zstd_data, dst, dst_size, src, src_size,1550 compressed = zstd_compress_stream_to_records(zstd_data, dst, dst_size, src, src_size,
1541 max_record_size, process_comp_header);1551 max_record_size, process_comp_header);
1552 if (compressed < 0)
1553 return compressed;
1542 1554
1543 if (map && map->file) {1555 if (map && map->file) {
1544 thread->bytes_transferred += src_size;1556 thread->bytes_transferred += src_size;
@@ -1912,21 +1924,13 @@ static void __record__save_lost_samples(struct record *rec, struct evsel *evsel, · 367 unmodified lines
1912static void record__read_lost_samples(struct record *rec)1924static void record__read_lost_samples(struct record *rec)
1913{1925{
1914 struct perf_session *session = rec->session;1926 struct perf_session *session = rec->session;
1915 struct perf_record_lost_samples *lost;1927 struct perf_record_lost_samples *lost = NULL;
1916 struct evsel *evsel;1928 struct evsel *evsel;
1917 1929
1918 /* there was an error during record__open */1930 /* there was an error during record__open */
1919 if (session->evlist == NULL)1931 if (session->evlist == NULL)
1920 return;1932 return;
1921 1933
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
1930 evlist__for_each_entry(session->evlist, evsel) {1934 evlist__for_each_entry(session->evlist, evsel) {
1931 struct xyarray *xy = evsel->core.sample_id;1935 struct xyarray *xy = evsel->core.sample_id;
1932 u64 lost_count;1936 u64 lost_count;
@@ -1949,6 +1953,15 @@ static void record__read_lost_samples(struct record *rec) · 16 unmodified lines
1949 }1953 }
1950 1954
1951 if (count.lost) {1955 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 }
1952 __record__save_lost_samples(rec, evsel, lost,1965 __record__save_lost_samples(rec, evsel, lost,
1953 x, y, count.lost, 0);1966 x, y, count.lost, 0);
1954 }1967 }
@@ -1956,9 +1969,19 @@ static void record__read_lost_samples(struct record *rec) · 1 unmodified line
1956 }1969 }
1957 1970
1958 lost_count = perf_bpf_filter__lost_count(evsel);1971 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 }
1960 __record__save_lost_samples(rec, evsel, lost, 0, 0, lost_count,1982 __record__save_lost_samples(rec, evsel, lost, 0, 0, lost_count,
1961 PERF_RECORD_MISC_LOST_SAMPLES_BPF);1983 PERF_RECORD_MISC_LOST_SAMPLES_BPF);
1984 }
1962 }1985 }
1963out:1986out:
1964 free(lost);1987 free(lost);
@@ -2216,32 +2239,6 @@ static void hit_auxtrace_snapshot_trigger(struct record *rec) · 251 unmodified lines
2216 }2239 }
2217}2240}
2218 2241
2219static 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
2245static int record__terminate_thread(struct record_thread *thread_data)2242static int record__terminate_thread(struct record_thread *thread_data)
2246{2243{
2247 int err;2244 int err;
@@ -2475,7 +2472,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) · 227 unmodified lines
2475 if (data->is_pipe && rec->evlist->core.nr_entries == 1)2472 if (data->is_pipe && rec->evlist->core.nr_entries == 1)
2476 rec->opts.sample_id = true;2473 rec->opts.sample_id = true;
2477 2474
2478 record__uniquify_name(rec);2475 evlist__uniquify_name(rec->evlist);
2479 2476
2480 /* Debug message used by test scripts */2477 /* Debug message used by test scripts */
2481 pr_debug3("perf record opening and mmapping events\n");2478 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
3580 if (cpu_map__is_dummy(cpus))3577 if (cpu_map__is_dummy(cpus))
3581 return 0;3578 return 0;
3582 3579
3583 perf_cpu_map__for_each_cpu(cpu, idx, cpus) {3580 perf_cpu_map__for_each_cpu_skip_any(cpu, idx, cpus) {
3584 if (cpu.cpu == -1)
3585 continue;
3586 /* Return ENODEV is input cpu is greater than max cpu */3581 /* Return ENODEV is input cpu is greater than max cpu */
3587 if ((unsigned long)cpu.cpu > mask->nbits)3582 if ((unsigned long)cpu.cpu > mask->nbits)
3588 return -ENODEV;3583 return -ENODEV;
@@ -3989,6 +3984,8 @@ int cmd_record(int argc, const char **argv) · 400 unmodified lines
3989# undef set_nobuild3984# undef set_nobuild
3990#endif3985#endif
3991 3986
3987 /* Disable eager loading of kernel symbols that adds overhead to perf record. */
3988 symbol_conf.lazy_load_kernel_maps = true;
3992 rec->opts.affinity = PERF_AFFINITY_SYS;3989 rec->opts.affinity = PERF_AFFINITY_SYS;
3993 3990
3994 rec->evlist = evlist__new();3991 rec->evlist = evlist__new();
tools/perf/builtin-report.c+74−39
@@ -96,9 +96,9 @@ struct report { · 95 unmodified lines
96 bool stitch_lbr;96 bool stitch_lbr;
97 bool disable_order;97 bool disable_order;
98 bool skip_empty;98 bool skip_empty;
99 bool data_type;
99 int max_stack;100 int max_stack;
100 struct perf_read_values show_threads_values;101 struct perf_read_values show_threads_values;
101 struct annotation_options annotation_opts;
102 const char *pretty_printing_style;102 const char *pretty_printing_style;
103 const char *cpu_list;103 const char *cpu_list;
104 const char *symbol_filter_str;104 const char *symbol_filter_str;
@@ -171,7 +171,7 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, · 66 unmodified lines
171 struct mem_info *mi;171 struct mem_info *mi;
172 struct branch_info *bi;172 struct branch_info *bi;
173 173
174 if (!ui__has_annotation() && !rep->symbol_ipc)174 if (!ui__has_annotation() && !rep->symbol_ipc && !rep->data_type)
175 return 0;175 return 0;
176 176
177 if (sort__mode == SORT_MODE__BRANCH) {177 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
541 evlist__for_each_entry(evlist, pos) {541 evlist__for_each_entry(evlist, pos) {
542 ret = report__browse_block_hists(&rep->block_reports[i++].hist,542 ret = report__browse_block_hists(&rep->block_reports[i++].hist,
543 rep->min_percent, pos,543 rep->min_percent, pos,
544 &rep->session->header.env,544 &rep->session->header.env);
545 &rep->annotation_opts);
546 if (ret != 0)545 if (ret != 0)
547 return ret;546 return ret;
548 }547 }
@@ -574,8 +573,7 @@ static int evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, c · 25 unmodified lines
574 573
575 if (rep->total_cycles_mode) {574 if (rep->total_cycles_mode) {
576 report__browse_block_hists(&rep->block_reports[i++].hist,575 report__browse_block_hists(&rep->block_reports[i++].hist,
577 rep->min_percent, pos,576 rep->min_percent, pos, NULL);
578 NULL, NULL);
579 continue;577 continue;
580 }578 }
581 579
@@ -670,7 +668,7 @@ static int report__browse_hists(struct report *rep) · 88 unmodified lines
670 }668 }
671 669
672 ret = evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent,670 ret = evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent,
673 &session->header.env, true, &rep->annotation_opts);671 &session->header.env, true);
674 /*672 /*
675 * Usually "ret" is the last pressed key, and we only673 * Usually "ret" is the last pressed key, and we only
676 * care if the key notifies us to switch data file.674 * 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
745 if (rep->symbol_ipc && sym && !sym->annotate2) {743 if (rep->symbol_ipc && sym && !sym->annotate2) {
746 struct evsel *evsel = hists_to_evsel(he->hists);744 struct evsel *evsel = hists_to_evsel(he->hists);
747 745
748 symbol__annotate2(&he->ms, evsel, &rep->annotation_opts, NULL);746 symbol__annotate2(&he->ms, evsel, NULL);
749 }747 }
750 748
751 return 0;749 return 0;
@@ -859,27 +857,47 @@ static struct task *tasks_list(struct task *task, struct machine *machine) · 107 unmodified lines
859 return tasks_list(parent_task, machine);857 return tasks_list(parent_task, machine);
860}858}
861 859
862static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)860struct maps__fprintf_task_args {
861 int indent;
862 FILE *fp;
863 size_t printed;
864};
865
866static int maps__fprintf_task_cb(struct map *map, void *data)
863{867{
864 size_t printed = 0;868 struct maps__fprintf_task_args *args = data;
865 struct map_rb_node *rb_node;869 const struct dso *dso = map__dso(map);
870 u32 prot = map__prot(map);
871 int ret;
866 872
867 maps__for_each_entry(maps, rb_node) {873 ret = fprintf(args->fp,
868 struct map *map = rb_node->map;874 "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n",
869 const struct dso *dso = map__dso(map);875 args->indent, "", map__start(map), map__end(map),
870 u32 prot = map__prot(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);
871 882
872 printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n",883 if (ret < 0)
873 indent, "", map__start(map), map__end(map),884 return ret;
874 prot & PROT_READ ? 'r' : '-',885
875 prot & PROT_WRITE ? 'w' : '-',886 args->printed += ret;
876 prot & PROT_EXEC ? 'x' : '-',887 return 0;
877 map__flags(map) ? 's' : 'p',888}
878 map__pgoff(map),889
879 dso->id.ino, dso->name);890static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
880 }891{
892 struct maps__fprintf_task_args args = {
893 .indent = indent,
894 .fp = fp,
895 .printed = 0,
896 };
881 897
882 return printed;898 maps__for_each_map(maps, maps__fprintf_task_cb, &args);
899
900 return args.printed;
883}901}
884 902
885static void task__print_level(struct task *task, FILE *fp, int level)903static 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
1341 "list of cpus to profile"),1359 "list of cpus to profile"),
1342 OPT_BOOLEAN('I', "show-info", &report.show_full_info,1360 OPT_BOOLEAN('I', "show-info", &report.show_full_info,
1343 "Display extended information about perf.data file"),1361 "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,
1345 "Interleave source code with assembly code (default)"),1363 "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,
1347 "Display raw encoding of assembly instructions (default)"),1365 "Display raw encoding of assembly instructions (default)"),
1348 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",1366 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1349 "Specify disassembler style (e.g. -M intel for intel syntax)"),1367 "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",
1351 "Add prefix to source file path names in programs (with --prefix-strip)"),1369 "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",
1353 "Strip first N entries of source file path name in programs (with --prefix)"),1371 "Strip first N entries of source file path name in programs (with --prefix)"),
1354 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,1372 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1355 "Show a column with the sum of periods"),1373 "Show a column with the sum of periods"),
@@ -1401,7 +1419,7 @@ int cmd_report(int argc, const char **argv) · 45 unmodified lines
1401 "Time span of interest (start,stop)"),1419 "Time span of interest (start,stop)"),
1402 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,1420 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
1403 "Show inline function"),1421 "Show inline function"),
1404 OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period",1422 OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period",
1405 "Set percent type local/global-period/hits",1423 "Set percent type local/global-period/hits",
1406 annotate_parse_percent_type),1424 annotate_parse_percent_type),
1407 OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, "Show times in nanosecs"),1425 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
1426 if (ret < 0)1444 if (ret < 0)
1427 goto exit;1445 goto exit;
1428 1446
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();
1430 1455
1431 ret = perf_config(report__config, &report);1456 ret = perf_config(report__config, &report);
1432 if (ret)1457 if (ret)
@@ -1445,13 +1470,13 @@ int cmd_report(int argc, const char **argv) · 12 unmodified lines
1445 }1470 }
1446 1471
1447 if (disassembler_style) {1472 if (disassembler_style) {
1448 report.annotation_opts.disassembler_style = strdup(disassembler_style);1473 annotate_opts.disassembler_style = strdup(disassembler_style);
1449 if (!report.annotation_opts.disassembler_style)1474 if (!annotate_opts.disassembler_style)
1450 return -ENOMEM;1475 return -ENOMEM;
1451 }1476 }
1452 if (objdump_path) {1477 if (objdump_path) {
1453 report.annotation_opts.objdump_path = strdup(objdump_path);1478 annotate_opts.objdump_path = strdup(objdump_path);
1454 if (!report.annotation_opts.objdump_path)1479 if (!annotate_opts.objdump_path)
1455 return -ENOMEM;1480 return -ENOMEM;
1456 }1481 }
1457 if (addr2line_path) {1482 if (addr2line_path) {
@@ -1460,7 +1485,7 @@ int cmd_report(int argc, const char **argv) · 2 unmodified lines
1460 return -ENOMEM;1485 return -ENOMEM;
1461 }1486 }
1462 1487
1463 if (annotate_check_args(&report.annotation_opts) < 0) {1488 if (annotate_check_args() < 0) {
1464 ret = -EINVAL;1489 ret = -EINVAL;
1465 goto exit;1490 goto exit;
1466 }1491 }
@@ -1615,6 +1640,16 @@ repeat: · 148 unmodified lines
1615 sort_order = NULL;1640 sort_order = NULL;
1616 }1641 }
1617 1642
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
1618 if (strcmp(input_name, "-") != 0)1653 if (strcmp(input_name, "-") != 0)
1619 setup_browser(true);1654 setup_browser(true);
1620 else1655 else
@@ -1673,7 +1708,7 @@ repeat: · 52 unmodified lines
1673 * so don't allocate extra space that won't be used in the stdio1708 * so don't allocate extra space that won't be used in the stdio
1674 * implementation.1709 * implementation.
1675 */1710 */
1676 if (ui__has_annotation() || report.symbol_ipc ||1711 if (ui__has_annotation() || report.symbol_ipc || report.data_type ||
1677 report.total_cycles_mode) {1712 report.total_cycles_mode) {
1678 ret = symbol__annotation_init();1713 ret = symbol__annotation_init();
1679 if (ret < 0)1714 if (ret < 0)
@@ -1692,7 +1727,7 @@ repeat: · 12 unmodified lines
1692 */1727 */
1693 symbol_conf.priv_size += sizeof(u32);1728 symbol_conf.priv_size += sizeof(u32);
1694 }1729 }
1695 annotation_config__init(&report.annotation_opts);1730 annotation_config__init();
1696 }1731 }
1697 1732
1698 if (symbol__init(&session->header.env) < 0)1733 if (symbol__init(&session->header.env) < 0)
@@ -1746,7 +1781,7 @@ error: · 47 unmodified lines
1746 zstd_fini(&(session->zstd_data));1781 zstd_fini(&(session->zstd_data));
1747 perf_session__delete(session);1782 perf_session__delete(session);
1748exit:1783exit:
1749 annotation_options__exit(&report.annotation_opts);1784 annotation_options__exit();
1750 free(sort_order_help);1785 free(sort_order_help);
1751 free(field_order_help);1786 free(field_order_help);
1752 return ret;1787 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
653 if ((evsel__leader(counter) != counter) ||653 if ((evsel__leader(counter) != counter) ||
654 !(counter->core.leader->nr_members > 1))654 !(counter->core.leader->nr_members > 1))
655 return COUNTER_SKIP;655 return COUNTER_SKIP;
656 } else if (evsel__fallback(counter, errno, msg, sizeof(msg))) {656 } else if (evsel__fallback(counter, &target, errno, msg, sizeof(msg))) {
657 if (verbose > 0)657 if (verbose > 0)
658 ui__warning("%s\n", msg);658 ui__warning("%s\n", msg);
659 return COUNTER_RETRY;659 return COUNTER_RETRY;
@@ -1204,8 +1204,9 @@ static struct option stat_options[] = { · 544 unmodified lines
1204 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",1204 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1205 "list of cpus to monitor in system-wide"),1205 "list of cpus to monitor in system-wide"),
1206 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,1206 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1207 "disable CPU count aggregation", AGGR_NONE),1207 "disable aggregation across CPUs or PMUs", AGGR_NONE),
1208 OPT_BOOLEAN(0, "no-merge", &stat_config.no_merge, "Do not merge identical named events"),1208 OPT_SET_UINT(0, "no-merge", &stat_config.aggr_mode,
1209 "disable aggregation the same as -A or -no-aggr", AGGR_NONE),
1209 OPT_BOOLEAN(0, "hybrid-merge", &stat_config.hybrid_merge,1210 OPT_BOOLEAN(0, "hybrid-merge", &stat_config.hybrid_merge,
1210 "Merge identical named hybrid events"),1211 "Merge identical named hybrid events"),
1211 OPT_STRING('x', "field-separator", &stat_config.csv_sep, "separator",1212 OPT_STRING('x', "field-separator", &stat_config.csv_sep, "separator",
@@ -1255,7 +1256,7 @@ static struct option stat_options[] = { · 43 unmodified lines
1255 OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge,1256 OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge,
1256 "don't try to share events between metrics in a group"),1257 "don't try to share events between metrics in a group"),
1257 OPT_BOOLEAN(0, "metric-no-threshold", &stat_config.metric_no_threshold,1258 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"),
1259 OPT_BOOLEAN(0, "topdown", &topdown_run,1260 OPT_BOOLEAN(0, "topdown", &topdown_run,
1260 "measure top-down statistics"),1261 "measure top-down statistics"),
1261 OPT_UINTEGER(0, "td-level", &stat_config.topdown_level,1262 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
1316 * be the first online CPU in the cache domain else use the1317 * be the first online CPU in the cache domain else use the
1317 * first online CPU of the cache domain as the ID.1318 * first online CPU of the cache domain as the ID.
1318 */1319 */
1319 if (perf_cpu_map__empty(cpu_map))1320 if (perf_cpu_map__has_any_cpu_or_is_empty(cpu_map))
1320 id = cpu.cpu;1321 id = cpu.cpu;
1321 else1322 else
1322 id = perf_cpu_map__cpu(cpu_map, 0).cpu;1323 id = perf_cpu_map__cpu(cpu_map, 0).cpu;
@@ -1622,7 +1623,7 @@ static int perf_stat_init_aggr_mode(void) · 299 unmodified lines
1622 * taking the highest cpu number to be the size of1623 * taking the highest cpu number to be the size of
1623 * the aggregation translate cpumap.1624 * the aggregation translate cpumap.
1624 */1625 */
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))
1626 nr = perf_cpu_map__max(evsel_list->core.user_requested_cpus).cpu;1627 nr = perf_cpu_map__max(evsel_list->core.user_requested_cpus).cpu;
1627 else1628 else
1628 nr = 0;1629 nr = 0;
@@ -2289,7 +2290,7 @@ int process_stat_config_event(struct perf_session *session, · 660 unmodified lines
2289 2290
2290 perf_event__read_stat_config(&stat_config, &event->stat_config);2291 perf_event__read_stat_config(&stat_config, &event->stat_config);
2291 2292
2292 if (perf_cpu_map__empty(st->cpus)) {2293 if (perf_cpu_map__has_any_cpu_or_is_empty(st->cpus)) {
2293 if (st->aggr_mode != AGGR_UNSET)2294 if (st->aggr_mode != AGGR_UNSET)
2294 pr_warning("warning: processing task data, aggregation mode not set\n");2295 pr_warning("warning: processing task data, aggregation mode not set\n");
2295 } else if (st->aggr_mode != AGGR_UNSET) {2296 } else if (st->aggr_mode != AGGR_UNSET) {
@@ -2695,15 +2696,19 @@ int cmd_stat(int argc, const char **argv) · 399 unmodified lines
2695 */2696 */
2696 if (metrics) {2697 if (metrics) {
2697 const char *pmu = parse_events_option_args.pmu_filter ?: "all";2698 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);
2698 2706
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);
2706 zfree(&metrics);2707 zfree(&metrics);
2708 if (ret) {
2709 status = ret;
2710 goto out;
2711 }
2707 }2712 }
2708 2713
2709 if (add_default_attributes())2714 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
147 return err;147 return err;
148 }148 }
149 149
150 err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL);150 err = symbol__annotate(&he->ms, evsel, NULL);
151 if (err == 0) {151 if (err == 0) {
152 top->sym_filter_entry = he;152 top->sym_filter_entry = he;
153 } else {153 } else {
@@ -261,9 +261,9 @@ static void perf_top__show_details(struct perf_top *top) · 107 unmodified lines
261 goto out_unlock;261 goto out_unlock;
262 262
263 printf("Showing %s for %s\n", evsel__name(top->sym_evsel), symbol->name);263 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);
265 265
266 more = symbol__annotate_printf(&he->ms, top->sym_evsel, &top->annotation_opts);266 more = symbol__annotate_printf(&he->ms, top->sym_evsel);
267 267
268 if (top->evlist->enabled) {268 if (top->evlist->enabled) {
269 if (top->zero)269 if (top->zero)
@@ -450,7 +450,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) · 180 unmodified lines
450 450
451 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);451 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
452 452
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);
454 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");454 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
455 fprintf(stdout, "\t[S] stop annotation.\n");455 fprintf(stdout, "\t[S] stop annotation.\n");
456 456
@@ -553,7 +553,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) · 96 unmodified lines
553 prompt_integer(&top->count_filter, "Enter display event count filter");553 prompt_integer(&top->count_filter, "Enter display event count filter");
554 break;554 break;
555 case 'F':555 case 'F':
556 prompt_percent(&top->annotation_opts.min_pcnt,556 prompt_percent(&annotate_opts.min_pcnt,
557 "Enter details display event filter (percent)");557 "Enter details display event filter (percent)");
558 break;558 break;
559 case 'K':559 case 'K':
@@ -646,8 +646,7 @@ repeat: · 86 unmodified lines
646 }646 }
647 647
648 ret = evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,648 ret = evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
649 &top->session->header.env, !top->record_opts.overwrite,649 &top->session->header.env, !top->record_opts.overwrite);
650 &top->annotation_opts);
651 if (ret == K_RELOAD) {650 if (ret == K_RELOAD) {
652 top->zero = true;651 top->zero = true;
653 goto repeat;652 goto repeat;
@@ -1027,8 +1026,8 @@ static int perf_top__start_counters(struct perf_top *top) · 373 unmodified lines
1027 1026
1028 evlist__for_each_entry(evlist, counter) {1027 evlist__for_each_entry(evlist, counter) {
1029try_again:1028try_again:
1030 if (evsel__open(counter, top->evlist->core.user_requested_cpus,1029 if (evsel__open(counter, counter->core.cpus,
1031 top->evlist->core.threads) < 0) {1030 counter->core.threads) < 0) {
1032 1031
1033 /*1032 /*
1034 * Specially handle overwrite fall back.1033 * Specially handle overwrite fall back.
@@ -1044,7 +1043,7 @@ try_again: · 9 unmodified lines
1044 perf_top_overwrite_fallback(top, counter))1043 perf_top_overwrite_fallback(top, counter))
1045 goto try_again;1044 goto try_again;
1046 1045
1047 if (evsel__fallback(counter, errno, msg, sizeof(msg))) {1046 if (evsel__fallback(counter, &opts->target, errno, msg, sizeof(msg))) {
1048 if (verbose > 0)1047 if (verbose > 0)
1049 ui__warning("%s\n", msg);1048 ui__warning("%s\n", msg);
1050 goto try_again;1049 goto try_again;
@@ -1241,9 +1240,9 @@ static int __cmd_top(struct perf_top *top) · 190 unmodified lines
1241 pthread_t thread, thread_process;1240 pthread_t thread, thread_process;
1242 int ret;1241 int ret;
1243 1242
1244 if (!top->annotation_opts.objdump_path) {1243 if (!annotate_opts.objdump_path) {
1245 ret = perf_env__lookup_objdump(&top->session->header.env,1244 ret = perf_env__lookup_objdump(&top->session->header.env,
1246 &top->annotation_opts.objdump_path);1245 &annotate_opts.objdump_path);
1247 if (ret)1246 if (ret)
1248 return ret;1247 return ret;
1249 }1248 }
@@ -1299,6 +1298,7 @@ static int __cmd_top(struct perf_top *top) · 49 unmodified lines
1299 }1298 }
1300 }1299 }
1301 1300
1301 evlist__uniquify_name(top->evlist);
1302 ret = perf_top__start_counters(top);1302 ret = perf_top__start_counters(top);
1303 if (ret)1303 if (ret)
1304 return ret;1304 return ret;
@@ -1536,9 +1536,9 @@ int cmd_top(int argc, const char **argv) · 231 unmodified lines
1536 "only consider symbols in these comms"),1536 "only consider symbols in these comms"),
1537 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",1537 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1538 "only consider these symbols"),1538 "only consider these symbols"),
1539 OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src,1539 OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src,
1540 "Interleave source code with assembly code (default)"),1540 "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,
1542 "Display raw encoding of assembly instructions (default)"),1542 "Display raw encoding of assembly instructions (default)"),
1543 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,1543 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
1544 "Enable kernel symbol demangling"),1544 "Enable kernel symbol demangling"),
@@ -1549,9 +1549,9 @@ int cmd_top(int argc, const char **argv) · 4 unmodified lines
1549 "addr2line binary to use for line numbers"),1549 "addr2line binary to use for line numbers"),
1550 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",1550 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1551 "Specify disassembler style (e.g. -M intel for intel syntax)"),1551 "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",
1553 "Add prefix to source file path names in programs (with --prefix-strip)"),1553 "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",
1555 "Strip first N entries of source file path name in programs (with --prefix)"),1555 "Strip first N entries of source file path name in programs (with --prefix)"),
1556 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),1556 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1557 OPT_CALLBACK(0, "percent-limit", &top, "percent",1557 OPT_CALLBACK(0, "percent-limit", &top, "percent",
@@ -1609,10 +1609,10 @@ int cmd_top(int argc, const char **argv) · 51 unmodified lines
1609 if (status < 0)1609 if (status < 0)
1610 return status;1610 return status;
1611 1611
1612 annotation_options__init(&top.annotation_opts);1612 annotation_options__init();
1613 1613
1614 top.annotation_opts.min_pcnt = 5;1614 annotate_opts.min_pcnt = 5;
1615 top.annotation_opts.context = 4;1615 annotate_opts.context = 4;
1616 1616
1617 top.evlist = evlist__new();1617 top.evlist = evlist__new();
1618 if (top.evlist == NULL)1618 if (top.evlist == NULL)
@@ -1642,13 +1642,13 @@ int cmd_top(int argc, const char **argv) · 23 unmodified lines
1642 usage_with_options(top_usage, options);1642 usage_with_options(top_usage, options);
1643 1643
1644 if (disassembler_style) {1644 if (disassembler_style) {
1645 top.annotation_opts.disassembler_style = strdup(disassembler_style);1645 annotate_opts.disassembler_style = strdup(disassembler_style);
1646 if (!top.annotation_opts.disassembler_style)1646 if (!annotate_opts.disassembler_style)
1647 return -ENOMEM;1647 return -ENOMEM;
1648 }1648 }
1649 if (objdump_path) {1649 if (objdump_path) {
1650 top.annotation_opts.objdump_path = strdup(objdump_path);1650 annotate_opts.objdump_path = strdup(objdump_path);
1651 if (!top.annotation_opts.objdump_path)1651 if (!annotate_opts.objdump_path)
1652 return -ENOMEM;1652 return -ENOMEM;
1653 }1653 }
1654 if (addr2line_path) {1654 if (addr2line_path) {
@@ -1661,7 +1661,7 @@ int cmd_top(int argc, const char **argv) · 6 unmodified lines
1661 if (status)1661 if (status)
1662 goto out_delete_evlist;1662 goto out_delete_evlist;
1663 1663
1664 if (annotate_check_args(&top.annotation_opts) < 0)1664 if (annotate_check_args() < 0)
1665 goto out_delete_evlist;1665 goto out_delete_evlist;
1666 1666
1667 if (!top.evlist->core.nr_entries) {1667 if (!top.evlist->core.nr_entries) {
@@ -1787,7 +1787,7 @@ int cmd_top(int argc, const char **argv) · 119 unmodified lines
1787 if (status < 0)1787 if (status < 0)
1788 goto out_delete_evlist;1788 goto out_delete_evlist;
1789 1789
1790 annotation_config__init(&top.annotation_opts);1790 annotation_config__init();
1791 1791
1792 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);1792 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1793 status = symbol__init(NULL);1793 status = symbol__init(NULL);
@@ -1840,7 +1840,7 @@ int cmd_top(int argc, const char **argv) · 46 unmodified lines
1840out_delete_evlist:1840out_delete_evlist:
1841 evlist__delete(top.evlist);1841 evlist__delete(top.evlist);
1842 perf_session__delete(top.session);1842 perf_session__delete(top.session);
1843 annotation_options__exit(&top.annotation_opts);1843 annotation_options__exit();
1844 1844
1845 return status;1845 return status;
1846}1846}
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
2470static const char *errno_to_name(struct evsel *evsel, int err)2470static const char *errno_to_name(struct evsel *evsel, int err)
2471{2471{
2472 struct perf_env *env = evsel__env(evsel);2472 struct perf_env *env = evsel__env(evsel);
2473 const char *arch_name = perf_env__arch(env);
2474 2473
2475 return arch_syscalls__strerrno(arch_name, err);2474 return perf_env__arch_strerrno(env, err);
2476}2475}
2477 2476
2478static int trace__sys_exit(struct trace *trace, struct evsel *evsel,2477static 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
4264 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);4263 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
4265 4264
4266 if (trace->errno_summary && stats->nr_failures) {4265 if (trace->errno_summary && stats->nr_failures) {
4267 const char *arch_name = perf_env__arch(trace->host->env);
4268 int e;4266 int e;
4269 4267
4270 for (e = 0; e < stats->max_errno; ++e) {4268 for (e = 0; e < stats->max_errno; ++e) {
4271 if (stats->errnos[e] != 0)4269 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]);
4273 }4271 }
4274 }4272 }
4275 }4273 }
tools/perf/perf-archive.sh+80−6
@@ -4,8 +4,73 @@ · 3 unmodified lines
4# Arnaldo Carvalho de Melo <acme@redhat.com>4# Arnaldo Carvalho de Melo <acme@redhat.com>
5 5
6PERF_DATA=perf.data6PERF_DATA=perf.data
7if [ $# -ne 0 ] ; then7PERF_SYMBOLS=perf.symbols
8 PERF_DATA=$18PERF_ALL=perf.all
9ALL=0
10UNPACK=0
11
12while [ $# -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
24done
25
26if [ $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
9fi74fi
10 75
11#76#
@@ -39,9 +104,18 @@ while read build_id ; do · 27 unmodified lines
39 echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST104 echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST
40done105done
41 106
42tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST107if [ $ALL -eq 1 ]; then # pack perf.data file together with tar containing debug symbols
43rm $MANIFEST $BUILDIDS || true108 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
113else # pack only the debug symbols
114 tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
115 rm $MANIFEST $BUILDIDS || true
116fi
117
44echo -e "Now please run:\n"118echo -e "Now please run:\n"
45echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"119echo -e "$ perf archive --unpack\n"
46echo "wherever you need to run 'perf report' on."120echo "or unpack the tar manually wherever you need to run 'perf report' on."
47exit 0121exit 0
tools/perf/perf.c+30−0
@@ -39,6 +39,7 @@ · 38 unmodified lines
39#include <linux/zalloc.h>39#include <linux/zalloc.h>
40 40
41static int use_pager = -1;41static int use_pager = -1;
42static FILE *debug_fp = NULL;
42 43
43struct cmd_struct {44struct cmd_struct {
44 const char *cmd;45 const char *cmd;
@@ -162,6 +163,19 @@ static void commit_pager_choice(void) · 117 unmodified lines
162 }163 }
163}164}
164 165
166static 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
165struct option options[] = {179struct option options[] = {
166 OPT_ARGUMENT("help", "help"),180 OPT_ARGUMENT("help", "help"),
167 OPT_ARGUMENT("version", "version"),181 OPT_ARGUMENT("version", "version"),
@@ -174,6 +188,7 @@ struct option options[] = { · 6 unmodified lines
174 OPT_ARGUMENT("list-cmds", "list-cmds"),188 OPT_ARGUMENT("list-cmds", "list-cmds"),
175 OPT_ARGUMENT("list-opts", "list-opts"),189 OPT_ARGUMENT("list-opts", "list-opts"),
176 OPT_ARGUMENT("debug", "debug"),190 OPT_ARGUMENT("debug", "debug"),
191 OPT_ARGUMENT("debug-file", "debug-file"),
177 OPT_END()192 OPT_END()
178};193};
179 194
@@ -287,6 +302,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) · 107 unmodified lines
287 302
288 (*argv)++;303 (*argv)++;
289 (*argc)--;304 (*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
290 } else {317 } else {
291 fprintf(stderr, "Unknown option: %s\n", cmd);318 fprintf(stderr, "Unknown option: %s\n", cmd);
292 usage(perf_usage_string);319 usage(perf_usage_string);
@@ -547,5 +574,8 @@ int main(int argc, const char **argv) · 254 unmodified lines
547 fprintf(stderr, "Failed to run command '%s': %s\n",574 fprintf(stderr, "Failed to run command '%s': %s\n",
548 cmd, str_error_r(errno, sbuf, sizeof(sbuf)));575 cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
549out:576out:
577 if (debug_fp)
578 fclose(debug_fp);
579
550 return 1;580 return 1;
551}581}
tools/perf/pmu-events/arch/arm64/ampere/ampereone/core-imp-def.json+1−1
@@ -110,7 +110,7 @@ · 109 unmodified lines
110 {110 {
111 "PublicDescription": "Flushes due to memory hazards",111 "PublicDescription": "Flushes due to memory hazards",
112 "EventCode": "0x121",112 "EventCode": "0x121",
113 "EventName": "BPU_FLUSH_MEM_FAULT",113 "EventName": "GPC_FLUSH_MEM_FAULT",
114 "BriefDescription": "Flushes due to memory hazards"114 "BriefDescription": "Flushes due to memory hazards"
115 },115 },
116 {116 {
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
107 "EventName": "hnf_qos_hh_retry",107 "EventName": "hnf_qos_hh_retry",
108 "EventidCode": "0xe",108 "EventidCode": "0xe",
109 "NodeType": "0x5",109 "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.",
111 "Unit": "arm_cmn",111 "Unit": "arm_cmn",
112 "Compat": "(434|436|43c|43a).*"112 "Compat": "(434|436|43c|43a).*"
113 },113 },
tools/perf/pmu-events/arch/arm64/mapfile.csv+1−0
@@ -42,3 +42,4 @@ · 41 unmodified lines
420x00000000480fd010,v1,hisilicon/hip08,core420x00000000480fd010,v1,hisilicon/hip08,core
430x00000000500f0000,v1,ampere/emag,core430x00000000500f0000,v1,ampere/emag,core
440x00000000c00fac30,v1,ampere/ampereone,core440x00000000c00fac30,v1,ampere/ampereone,core
450x00000000c00fac40,v1,ampere/ampereonex,core
tools/perf/pmu-events/arch/powerpc/mapfile.csv+1−2
@@ -11,8 +11,7 @@ · 10 unmodified lines
11#11#
12# Multiple PVRs could map to a single JSON file.12# Multiple PVRs could map to a single JSON file.
13#13#
14
15# Power8 entries
160x004[bcd][[:xdigit:]]{4},1,power8,core140x004[bcd][[:xdigit:]]{4},1,power8,core
150x0066[[:xdigit:]]{4},1,power8,core
170x004e[[:xdigit:]]{4},1,power9,core160x004e[[:xdigit:]]{4},1,power9,core
180x0080[[:xdigit:]]{4},1,power10,core170x0080[[:xdigit:]]{4},1,power10,core
tools/perf/pmu-events/arch/powerpc/power10/datasource.json+14−4
@@ -99,6 +99,11 @@ · 98 unmodified lines
99 "EventName": "PM_INST_FROM_L2MISS",99 "EventName": "PM_INST_FROM_L2MISS",
100 "BriefDescription": "The processor's instruction cache was reloaded from a source beyond the local core's L2 due to a demand miss."100 "BriefDescription": "The processor's instruction cache was reloaded from a source beyond the local core's L2 due to a demand miss."
101 },101 },
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 },
102 {107 {
103 "EventCode": "0x000380000010C040",108 "EventCode": "0x000380000010C040",
104 "EventName": "PM_INST_FROM_L2MISS_ALL",109 "EventName": "PM_INST_FROM_L2MISS_ALL",
@@ -161,9 +166,14 @@ · 56 unmodified lines
161 },166 },
162 {167 {
163 "EventCode": "0x000780000000C040",168 "EventCode": "0x000780000000C040",
164 "EventName": "PM_INST_FROM_L3MISS",169 "EventName": "PM_INST_FROM_L3MISS_DSRC",
165 "BriefDescription": "The processor's instruction cache was reloaded from beyond the local core's L3 due to a demand miss."170 "BriefDescription": "The processor's instruction cache was reloaded from beyond the local core's L3 due to a demand miss."
166 },171 },
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 },
167 {177 {
168 "EventCode": "0x000780000010C040",178 "EventCode": "0x000780000010C040",
169 "EventName": "PM_INST_FROM_L3MISS_ALL",179 "EventName": "PM_INST_FROM_L3MISS_ALL",
@@ -981,7 +991,7 @@ · 811 unmodified lines
981 },991 },
982 {992 {
983 "EventCode": "0x0003C0000000C142",993 "EventCode": "0x0003C0000000C142",
984 "EventName": "PM_MRK_DATA_FROM_L2MISS",994 "EventName": "PM_MRK_DATA_FROM_L2MISS_DSRC",
985 "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."995 "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."
986 },996 },
987 {997 {
@@ -1046,12 +1056,12 @@ · 58 unmodified lines
1046 },1056 },
1047 {1057 {
1048 "EventCode": "0x000780000000C142",1058 "EventCode": "0x000780000000C142",
1049 "EventName": "PM_MRK_INST_FROM_L3MISS",1059 "EventName": "PM_MRK_INST_FROM_L3MISS_DSRC",
1050 "BriefDescription": "The processor's instruction cache was reloaded from beyond the local core's L3 due to a demand miss for a marked instruction."1060 "BriefDescription": "The processor's instruction cache was reloaded from beyond the local core's L3 due to a demand miss for a marked instruction."
1051 },1061 },
1052 {1062 {
1053 "EventCode": "0x0007C0000000C142",1063 "EventCode": "0x0007C0000000C142",
1054 "EventName": "PM_MRK_DATA_FROM_L3MISS",1064 "EventName": "PM_MRK_DATA_FROM_L3MISS_DSRC",
1055 "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."1065 "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."
1056 },1066 },
1057 {1067 {
tools/perf/pmu-events/arch/riscv/mapfile.csv+2−0
@@ -15,3 +15,5 @@ · 14 unmodified lines
15#15#
16#MVENDORID-MARCHID-MIMPID,Version,Filename,EventType16#MVENDORID-MARCHID-MIMPID,Version,Filename,EventType
170x489-0x8000000000000007-0x[[:xdigit:]]+,v1,sifive/u74,core170x489-0x8000000000000007-0x[[:xdigit:]]+,v1,sifive/u74,core
180x5b7-0x0-0x0,v1,thead/c900-legacy,core
190x67e-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
69 "MetricName": "C9_Pkg_Residency",69 "MetricName": "C9_Pkg_Residency",
70 "ScaleUnit": "100%"70 "ScaleUnit": "100%"
71 },71 },
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 },
78 {72 {
79 "BriefDescription": "Percentage of cycles spent in System Management Interrupts.",73 "BriefDescription": "Percentage of cycles spent in System Management Interrupts.",
80 "MetricExpr": "((msr@aperf@ - cycles) / msr@aperf@ if msr@smi@ > 0 else 0)",74 "MetricExpr": "((msr@aperf@ - cycles) / msr@aperf@ if msr@smi@ > 0 else 0)",
@@ -809,6 +803,13 @@ · 728 unmodified lines
809 "ScaleUnit": "100%",803 "ScaleUnit": "100%",
810 "Unit": "cpu_atom"804 "Unit": "cpu_atom"
811 },805 },
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 },
812 {813 {
813 "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.",814 "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.",
814 "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)",815 "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
1838 },1839 },
1839 {1840 {
1840 "BriefDescription": "Average number of parallel data read requests to external memory",1841 "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@",
1842 "MetricGroup": "Mem;MemoryBW;SoC",1843 "MetricGroup": "Mem;MemoryBW;SoC",
1843 "MetricName": "tma_info_system_mem_parallel_reads",1844 "MetricName": "tma_info_system_mem_parallel_reads",
1844 "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches",1845 "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
330 "MetricGroup": "data_fabric",330 "MetricGroup": "data_fabric",
331 "PerPkg": "1",331 "PerPkg": "1",
332 "ScaleUnit": "6.103515625e-5MiB"332 "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"
333 }417 }
334]418]
tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json+6−0
@@ -1862,6 +1862,12 @@ · 1861 unmodified lines
1862 "MetricName": "uncore_frequency",1862 "MetricName": "uncore_frequency",
1863 "ScaleUnit": "1GHz"1863 "ScaleUnit": "1GHz"
1864 },1864 },
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 },
1865 {1871 {
1866 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",1872 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
1867 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",1873 "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
23 "UMask": "0x10"23 "UMask": "0x10"
24 },24 },
25 {25 {
26 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0",26 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]",
27 "EventCode": "0xb3",27 "EventCode": "0xb3",
28 "EventName": "FP_ARITH_DISPATCHED.PORT_0",28 "EventName": "FP_ARITH_DISPATCHED.PORT_0",
29 "SampleAfterValue": "2000003",29 "SampleAfterValue": "2000003",
30 "UMask": "0x1"30 "UMask": "0x1"
31 },31 },
32 {32 {
33 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1",33 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]",
34 "EventCode": "0xb3",34 "EventCode": "0xb3",
35 "EventName": "FP_ARITH_DISPATCHED.PORT_1",35 "EventName": "FP_ARITH_DISPATCHED.PORT_1",
36 "SampleAfterValue": "2000003",36 "SampleAfterValue": "2000003",
37 "UMask": "0x2"37 "UMask": "0x2"
38 },38 },
39 {39 {
40 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5",40 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]",
41 "EventCode": "0xb3",41 "EventCode": "0xb3",
42 "EventName": "FP_ARITH_DISPATCHED.PORT_5",42 "EventName": "FP_ARITH_DISPATCHED.PORT_5",
43 "SampleAfterValue": "2000003",43 "SampleAfterValue": "2000003",
44 "UMask": "0x4"44 "UMask": "0x4"
45 },45 },
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 },
46 {67 {
47 "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.",68 "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.",
48 "EventCode": "0xc7",69 "EventCode": "0xc7",
tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json+1−17
@@ -1,20 +1,4 @@
1[1[
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 },
18 {2 {
19 "BriefDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE",3 "BriefDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE",
20 "CounterMask": "1",4 "CounterMask": "1",
@@ -505,7 +489,7 @@ · 484 unmodified lines
505 "UMask": "0x1"489 "UMask": "0x1"
506 },490 },
507 {491 {
508 "BriefDescription": "INT_MISC.UNKNOWN_BRANCH_CYCLES",492 "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).",
509 "EventCode": "0xad",493 "EventCode": "0xad",
510 "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES",494 "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES",
511 "MSRIndex": "0x3F7",495 "MSRIndex": "0x3F7",
tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json+4−4
@@ -4825,11 +4825,11 @@ · 4824 unmodified lines
4825 "Unit": "M3UPI"4825 "Unit": "M3UPI"
4826 },4826 },
4827 {4827 {
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)",
4829 "EventCode": "0x47",4829 "EventCode": "0x47",
4830 "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC",4830 "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC",
4831 "PerPkg": "1",4831 "PerPkg": "1",
4832 "PublicDescription": "AD Bouncable : Number of allocations into the CRS Egress",4832 "PublicDescription": "AD Bounceable : Number of allocations into the CRS Egress",
4833 "UMask": "0x1",4833 "UMask": "0x1",
4834 "Unit": "MDF"4834 "Unit": "MDF"
4835 },4835 },
@@ -4861,11 +4861,11 @@ · 25 unmodified lines
4861 "Unit": "MDF"4861 "Unit": "MDF"
4862 },4862 },
4863 {4863 {
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)",
4865 "EventCode": "0x47",4865 "EventCode": "0x47",
4866 "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC",4866 "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC",
4867 "PerPkg": "1",4867 "PerPkg": "1",
4868 "PublicDescription": "BL Bouncable : Number of allocations into the CRS Egress",4868 "PublicDescription": "BL Bounceable : Number of allocations into the CRS Egress",
4869 "UMask": "0x4",4869 "UMask": "0x4",
4870 "Unit": "MDF"4870 "Unit": "MDF"
4871 },4871 },
tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json+30−0
@@ -1185,6 +1185,36 @@ · 1184 unmodified lines
1185 "UMask": "0x70ff010",1185 "UMask": "0x70ff010",
1186 "Unit": "IIO"1186 "Unit": "IIO"
1187 },1187 },
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 },
1188 {1218 {
1189 "BriefDescription": ": Context cache hits",1219 "BriefDescription": ": Context cache hits",
1190 "EventCode": "0x40",1220 "EventCode": "0x40",
tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json+6−0
@@ -1846,6 +1846,12 @@ · 1845 unmodified lines
1846 "MetricName": "uncore_frequency",1846 "MetricName": "uncore_frequency",
1847 "ScaleUnit": "1GHz"1847 "ScaleUnit": "1GHz"
1848 },1848 },
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 },
1849 {1855 {
1850 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",1856 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
1851 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",1857 "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
19 "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule.",19 "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule.",
20 "EventCode": "0x28",20 "EventCode": "0x28",
21 "EventName": "CORE_POWER.LVL2_TURBO_LICENSE",21 "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.",
23 "SampleAfterValue": "200003",23 "SampleAfterValue": "200003",
24 "UMask": "0x20"24 "UMask": "0x20"
25 },25 },
tools/perf/pmu-events/arch/x86/icelakex/pipeline.json+1−1
@@ -519,7 +519,7 @@ · 518 unmodified lines
519 "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread",519 "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread",
520 "EventCode": "0x5e",520 "EventCode": "0x5e",
521 "EventName": "RS_EVENTS.EMPTY_CYCLES",521 "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)",
523 "SampleAfterValue": "1000003",523 "SampleAfterValue": "1000003",
524 "UMask": "0x1"524 "UMask": "0x1"
525 },525 },
tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json+3−3
@@ -38,7 +38,7 @@ · 37 unmodified lines
38 "EventCode": "0x10",38 "EventCode": "0x10",
39 "EventName": "UNC_I_COHERENT_OPS.CLFLUSH",39 "EventName": "UNC_I_COHERENT_OPS.CLFLUSH",
40 "PerPkg": "1",40 "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",
42 "UMask": "0x80",42 "UMask": "0x80",
43 "Unit": "IRP"43 "Unit": "IRP"
44 },44 },
@@ -65,7 +65,7 @@ · 20 unmodified lines
65 "EventCode": "0x10",65 "EventCode": "0x10",
66 "EventName": "UNC_I_COHERENT_OPS.WBMTOI",66 "EventName": "UNC_I_COHERENT_OPS.WBMTOI",
67 "PerPkg": "1",67 "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",
69 "UMask": "0x40",69 "UMask": "0x40",
70 "Unit": "IRP"70 "Unit": "IRP"
71 },71 },
@@ -454,7 +454,7 @@ · 382 unmodified lines
454 "EventCode": "0x11",454 "EventCode": "0x11",
455 "EventName": "UNC_I_TRANSACTIONS.WRITES",455 "EventName": "UNC_I_TRANSACTIONS.WRITES",
456 "PerPkg": "1",456 "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.",
458 "UMask": "0x2",458 "UMask": "0x2",
459 "Unit": "IRP"459 "Unit": "IRP"
460 },460 },
tools/perf/pmu-events/arch/x86/mapfile.csv+3−3
@@ -7,7 +7,7 @@ GenuineIntel-6-56,v11,broadwellde,core · 6 unmodified lines
7GenuineIntel-6-4F,v22,broadwellx,core7GenuineIntel-6-4F,v22,broadwellx,core
8GenuineIntel-6-55-[56789ABCDEF],v1.20,cascadelakex,core8GenuineIntel-6-55-[56789ABCDEF],v1.20,cascadelakex,core
9GenuineIntel-6-9[6C],v1.04,elkhartlake,core9GenuineIntel-6-9[6C],v1.04,elkhartlake,core
10GenuineIntel-6-CF,v1.01,emeraldrapids,core10GenuineIntel-6-CF,v1.02,emeraldrapids,core
11GenuineIntel-6-5[CF],v13,goldmont,core11GenuineIntel-6-5[CF],v13,goldmont,core
12GenuineIntel-6-7A,v1.01,goldmontplus,core12GenuineIntel-6-7A,v1.01,goldmontplus,core
13GenuineIntel-6-B6,v1.00,grandridge,core13GenuineIntel-6-B6,v1.00,grandridge,core
@@ -15,7 +15,7 @@ GenuineIntel-6-A[DE],v1.01,graniterapids,core · 1 unmodified line
15GenuineIntel-6-(3C|45|46),v33,haswell,core15GenuineIntel-6-(3C|45|46),v33,haswell,core
16GenuineIntel-6-3F,v28,haswellx,core16GenuineIntel-6-3F,v28,haswellx,core
17GenuineIntel-6-7[DE],v1.19,icelake,core17GenuineIntel-6-7[DE],v1.19,icelake,core
18GenuineIntel-6-6[AC],v1.21,icelakex,core18GenuineIntel-6-6[AC],v1.23,icelakex,core
19GenuineIntel-6-3A,v24,ivybridge,core19GenuineIntel-6-3A,v24,ivybridge,core
20GenuineIntel-6-3E,v24,ivytown,core20GenuineIntel-6-3E,v24,ivytown,core
21GenuineIntel-6-2D,v24,jaketown,core21GenuineIntel-6-2D,v24,jaketown,core
@@ -26,7 +26,7 @@ GenuineIntel-6-1[AEF],v4,nehalemep,core · 4 unmodified lines
26GenuineIntel-6-2E,v4,nehalemex,core26GenuineIntel-6-2E,v4,nehalemex,core
27GenuineIntel-6-A7,v1.01,rocketlake,core27GenuineIntel-6-A7,v1.01,rocketlake,core
28GenuineIntel-6-2A,v19,sandybridge,core28GenuineIntel-6-2A,v19,sandybridge,core
29GenuineIntel-6-8F,v1.16,sapphirerapids,core29GenuineIntel-6-8F,v1.17,sapphirerapids,core
30GenuineIntel-6-AF,v1.00,sierraforest,core30GenuineIntel-6-AF,v1.00,sierraforest,core
31GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core31GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core
32GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v57,skylake,core32GenuineIntel-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
985 },985 },
986 {986 {
987 "BriefDescription": "Average number of parallel data read requests to external memory",987 "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@",
989 "MetricGroup": "Mem;MemoryBW;SoC",989 "MetricGroup": "Mem;MemoryBW;SoC",
990 "MetricName": "tma_info_system_mem_parallel_reads",990 "MetricName": "tma_info_system_mem_parallel_reads",
991 "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches"991 "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
23 "UMask": "0x10"23 "UMask": "0x10"
24 },24 },
25 {25 {
26 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0",26 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]",
27 "EventCode": "0xb3",27 "EventCode": "0xb3",
28 "EventName": "FP_ARITH_DISPATCHED.PORT_0",28 "EventName": "FP_ARITH_DISPATCHED.PORT_0",
29 "SampleAfterValue": "2000003",29 "SampleAfterValue": "2000003",
30 "UMask": "0x1"30 "UMask": "0x1"
31 },31 },
32 {32 {
33 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1",33 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]",
34 "EventCode": "0xb3",34 "EventCode": "0xb3",
35 "EventName": "FP_ARITH_DISPATCHED.PORT_1",35 "EventName": "FP_ARITH_DISPATCHED.PORT_1",
36 "SampleAfterValue": "2000003",36 "SampleAfterValue": "2000003",
37 "UMask": "0x2"37 "UMask": "0x2"
38 },38 },
39 {39 {
40 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5",40 "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]",
41 "EventCode": "0xb3",41 "EventCode": "0xb3",
42 "EventName": "FP_ARITH_DISPATCHED.PORT_5",42 "EventName": "FP_ARITH_DISPATCHED.PORT_5",
43 "SampleAfterValue": "2000003",43 "SampleAfterValue": "2000003",
44 "UMask": "0x4"44 "UMask": "0x4"
45 },45 },
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 },
46 {67 {
47 "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.",68 "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.",
48 "EventCode": "0xc7",69 "EventCode": "0xc7",
tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json+1−1
@@ -505,7 +505,7 @@ · 504 unmodified lines
505 "UMask": "0x1"505 "UMask": "0x1"
506 },506 },
507 {507 {
508 "BriefDescription": "INT_MISC.UNKNOWN_BRANCH_CYCLES",508 "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).",
509 "EventCode": "0xad",509 "EventCode": "0xad",
510 "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES",510 "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES",
511 "MSRIndex": "0x3F7",511 "MSRIndex": "0x3F7",
tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json+6−0
@@ -1964,6 +1964,12 @@ · 1963 unmodified lines
1964 "MetricName": "uncore_frequency",1964 "MetricName": "uncore_frequency",
1965 "ScaleUnit": "1GHz"1965 "ScaleUnit": "1GHz"
1966 },1966 },
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 },
1967 {1973 {
1968 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",1974 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
1969 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",1975 "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
4825 "Unit": "M3UPI"4825 "Unit": "M3UPI"
4826 },4826 },
4827 {4827 {
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)",
4829 "EventCode": "0x47",4829 "EventCode": "0x47",
4830 "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC",4830 "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC",
4831 "PerPkg": "1",4831 "PerPkg": "1",
4832 "PublicDescription": "AD Bouncable : Number of allocations into the CRS Egress",4832 "PublicDescription": "AD Bounceable : Number of allocations into the CRS Egress",
4833 "UMask": "0x1",4833 "UMask": "0x1",
4834 "Unit": "MDF"4834 "Unit": "MDF"
4835 },4835 },
@@ -4861,11 +4861,11 @@ · 25 unmodified lines
4861 "Unit": "MDF"4861 "Unit": "MDF"
4862 },4862 },
4863 {4863 {
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)",
4865 "EventCode": "0x47",4865 "EventCode": "0x47",
4866 "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC",4866 "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC",
4867 "PerPkg": "1",4867 "PerPkg": "1",
4868 "PublicDescription": "BL Bouncable : Number of allocations into the CRS Egress",4868 "PublicDescription": "BL Bounceable : Number of allocations into the CRS Egress",
4869 "UMask": "0x4",4869 "UMask": "0x4",
4870 "Unit": "MDF"4870 "Unit": "MDF"
4871 },4871 },
tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json+30−0
@@ -1249,6 +1249,36 @@ · 1248 unmodified lines
1249 "UMask": "0x70ff010",1249 "UMask": "0x70ff010",
1250 "Unit": "IIO"1250 "Unit": "IIO"
1251 },1251 },
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 },
1252 {1282 {
1253 "BriefDescription": ": Context cache hits",1283 "BriefDescription": ": Context cache hits",
1254 "EventCode": "0x40",1284 "EventCode": "0x40",
tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json+6−0
@@ -1806,6 +1806,12 @@ · 1805 unmodified lines
1806 "MetricName": "uncore_frequency",1806 "MetricName": "uncore_frequency",
1807 "ScaleUnit": "1GHz"1807 "ScaleUnit": "1GHz"
1808 },1808 },
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 },
1809 {1815 {
1810 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",1816 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
1811 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",1817 "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
83 """Return the length of s a C string83 """Return the length of s a C string
84 84
85 This doesn't handle all escape characters properly. It first assumes85 This doesn't handle all escape characters properly. It first assumes
86 all \ are for escaping, it then adjusts as it will have over counted86 all \\ are for escaping, it then adjusts as it will have over counted
87 \\. The code uses \000 rather than \0 as a terminator as an adjacent87 \\. The code uses \000 rather than \0 as a terminator as an adjacent
88 number would be folded into a string of \0 (ie. "\0" + "5" doesn't88 number would be folded into a string of \0 (ie. "\0" + "5" doesn't
89 equal a terminator followed by the number 5 but the escape of89 equal a terminator followed by the number 5 but the escape of
@@ -286,6 +286,7 @@ class JsonEvent: · 196 unmodified lines
286 'imx8_ddr': 'imx8_ddr',286 'imx8_ddr': 'imx8_ddr',
287 'L3PMC': 'amd_l3',287 'L3PMC': 'amd_l3',
288 'DFPMC': 'amd_df',288 'DFPMC': 'amd_df',
289 'UMCPMC': 'amd_umc',
289 'cpu_core': 'cpu_core',290 'cpu_core': 'cpu_core',
290 'cpu_atom': 'cpu_atom',291 'cpu_atom': 'cpu_atom',
291 'ali_drw': 'ali_drw',292 'ali_drw': 'ali_drw',
@@ -354,6 +355,7 @@ class JsonEvent: · 62 unmodified lines
354 ('SampleAfterValue', 'period='),355 ('SampleAfterValue', 'period='),
355 ('UMask', 'umask='),356 ('UMask', 'umask='),
356 ('NodeType', 'type='),357 ('NodeType', 'type='),
358 ('RdWrMask', 'rdwrmask='),
357 ]359 ]
358 for key, value in event_fields:360 for key, value in event_fields:
359 if key in jd and jd[key] != '0':361 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
45# Initialize global dicts and regular expression45# Initialize global dicts and regular expression
46disasm_cache = dict()46disasm_cache = dict()
47cpu_data = dict()47cpu_data = dict()
48disasm_re = re.compile("^\s*([0-9a-fA-F]+):")48disasm_re = re.compile(r"^\s*([0-9a-fA-F]+):")
49disasm_func_re = re.compile("^\s*([0-9a-fA-F]+)\s.*:")49disasm_func_re = re.compile(r"^\s*([0-9a-fA-F]+)\s.*:")
50cache_size = 64*102450cache_size = 64*1024
51 51
52glb_source_file_name = None52glb_source_file_name = None
@@ -188,6 +188,17 @@ def process_event(param_dict): · 135 unmodified lines
188 dso_end = get_optional(param_dict, "dso_map_end")188 dso_end = get_optional(param_dict, "dso_map_end")
189 symbol = get_optional(param_dict, "symbol")189 symbol = get_optional(param_dict, "symbol")
190 190
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
191 if (options.verbose == True):202 if (options.verbose == True):
192 print("Event type: %s" % name)203 print("Event type: %s" % name)
193 print_sample(sample)204 print_sample(sample)
@@ -209,16 +220,6 @@ def process_event(param_dict): · 15 unmodified lines
209 if (name[0:8] != "branches"):220 if (name[0:8] != "branches"):
210 return221 return
211 222
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
222 # The format for packet is:223 # The format for packet is:
223 #224 #
224 # +------------+------------+------------+225 # +------------+------------+------------+
@@ -258,8 +259,9 @@ def process_event(param_dict): · 33 unmodified lines
258 259
259 if (options.objdump_name != None):260 if (options.objdump_name != None):
260 # It doesn't need to decrease virtual memory offset for disassembly261 # 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 # for kernel dso and executable file dso, so in this case we set
262 if (dso == "[kernel.kallsyms]"):263 # vm_start to zero.
264 if (dso == "[kernel.kallsyms]" or dso_start == 0x400000):
263 dso_vm_start = 0265 dso_vm_start = 0
264 else:266 else:
265 dso_vm_start = int(dso_start)267 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
260 260
261comm_re = None261comm_re = None
262pid_re = None262pid_re = None
263pid_regex = "^(\d*)-(\d*)$|^(\d*)$"263pid_regex = r"^(\d*)-(\d*)$|^(\d*)$"
264 264
265opt_proc = popt.DISP_DFL265opt_proc = popt.DISP_DFL
266opt_disp = topt.DISP_ALL266opt_disp = topt.DISP_ALL
tools/perf/scripts/python/exported-sql-viewer.py+2−2
@@ -677,8 +677,8 @@ class CallGraphModelBase(TreeModel): · 676 unmodified lines
677 # sqlite supports GLOB (text only) which uses * and ? and is case sensitive677 # sqlite supports GLOB (text only) which uses * and ? and is case sensitive
678 if not self.glb.dbref.is_sqlite3:678 if not self.glb.dbref.is_sqlite3:
679 # Escape % and _679 # Escape % and _
680 s = value.replace("%", "\%")680 s = value.replace("%", "\\%")
681 s = s.replace("_", "\_")681 s = s.replace("_", "\\_")
682 # Translate * and ? into SQL LIKE pattern characters % and _682 # Translate * and ? into SQL LIKE pattern characters % and _
683 trans = string.maketrans("*?", "%_")683 trans = string.maketrans("*?", "%_")
684 match = " LIKE '" + str(s).translate(trans) + "'"684 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
77CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls77CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls
78 78
79perf-y += workloads/79perf-y += workloads/
80
81ifdef SHELLCHECK
82 SHELL_TESTS := $(shell find tests/shell -executable -type f -name '*.sh')
83 TEST_LOGS := $(SHELL_TESTS:tests/shell/%=shell/%.shellcheck_log)
84else
85 SHELL_TESTS :=
86 TEST_LOGS :=
87endif
88
89$(OUTPUT)%.shellcheck_log: %
90 $(call rule_mkdir)
91 $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false)
92
93perf-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
188 if (perf_pmus__num_core_pmus() > 1) {188 if (perf_pmus__num_core_pmus() > 1) {
189 /*189 /*
190 * TODO: Attribute tests hard code the PMU type. If there are >1190 * TODO: Attribute tests hard code the PMU type. If there are >1
191 * core PMU then each PMU will have a different type whic191 * core PMU then each PMU will have a different type which
192 * requires additional support.192 * requires additional support.
193 */193 */
194 pr_debug("Skip test on hybrid systems");194 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
6cpu=*6cpu=*
7type=0|17type=0|1
8size=1368size=136
9config=09config=0|1
10sample_period=*10sample_period=*
11sample_type=26311sample_type=263
12read_format=0|4|2012read_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
6ret = 1296ret = 129
7test_ret = true7test_ret = true
8arch = aarch648arch = aarch64
9auxv = auxv["AT_HWCAP"] & 0x200000 == 09auxv = 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
6ret = 16ret = 1
7test_ret = true7test_ret = true
8arch = aarch648arch = aarch64
9auxv = auxv["AT_HWCAP"] & 0x200000 == 0x2000009auxv = auxv["AT_HWCAP"] & 0x400000 == 0x400000
10kernel_since = 6.110kernel_since = 6.1
11 11
12[event:base-record]12[event:base-record]
tools/perf/tests/builtin-test.c+15−2
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#include <sys/wait.h>14#include <sys/wait.h>
15#include <sys/stat.h>15#include <sys/stat.h>
16#include "builtin.h"16#include "builtin.h"
17#include "config.h"
17#include "hist.h"18#include "hist.h"
18#include "intlist.h"19#include "intlist.h"
19#include "tests.h"20#include "tests.h"
@@ -32,6 +33,7 @@ · 12 unmodified lines
32 33
33static bool dont_fork;34static bool dont_fork;
34const char *dso_to_test;35const char *dso_to_test;
36const char *test_objdump_path = "objdump";
35 37
36/*38/*
37 * List of architecture specific tests. Not a weak symbol as the array length is39 * 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
60 &suite__pmu,62 &suite__pmu,
61 &suite__pmu_events,63 &suite__pmu_events,
62 &suite__dso_data,64 &suite__dso_data,
63 &suite__dso_data_cache,
64 &suite__dso_data_reopen,
65 &suite__perf_evsel__roundtrip_name_test,65 &suite__perf_evsel__roundtrip_name_test,
66#ifdef HAVE_LIBTRACEEVENT66#ifdef HAVE_LIBTRACEEVENT
67 &suite__perf_evsel__tp_sched_test,67 &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
513 return -1;513 return -1;
514}514}
515 515
516static 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
516int cmd_test(int argc, const char **argv)525int cmd_test(int argc, const char **argv)
517{526{
518 const char *test_usage[] = {527 const char *test_usage[] = {
@@ -529,6 +538,8 @@ int cmd_test(int argc, const char **argv) · 10 unmodified lines
529 "Do not fork for testcase"),538 "Do not fork for testcase"),
530 OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"),539 OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"),
531 OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"),540 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"),
532 OPT_END()543 OPT_END()
533 };544 };
534 const char * const test_subcommands[] = { "list", NULL };545 const char * const test_subcommands[] = { "list", NULL };
@@ -538,6 +549,8 @@ int cmd_test(int argc, const char **argv) · 3 unmodified lines
538 if (ret < 0)549 if (ret < 0)
539 return ret;550 return ret;
540 551
552 perf_config(perf_test__config, NULL);
553
541 /* Unbuffered output */554 /* Unbuffered output */
542 setvbuf(stdout, NULL, _IONBF, 0);555 setvbuf(stdout, NULL, _IONBF, 0);
543 556
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
185 int ret;185 int ret;
186 186
187 fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";187 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,
189 filename);189 filename);
190 if (ret <= 0 || (size_t)ret >= sizeof(cmd))190 if (ret <= 0 || (size_t)ret >= sizeof(cmd))
191 return -1;191 return -1;
@@ -511,38 +511,6 @@ static void fs_something(void) · 319 unmodified lines
511 }511 }
512}512}
513 513
514#ifdef __s390x__
515#include "header.h" // for get_cpuid()
516#endif
517
518static 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 */
539out_clocks:
540 event = excl_kernel ? "cpu-clock:u" : "cpu-clock";
541
542#endif
543 return event;
544}
545
546static void do_something(void)514static void do_something(void)
547{515{
548 fs_something();516 fs_something();
@@ -583,8 +551,10 @@ static int do_test_code_reading(bool try_kcore) · 34 unmodified lines
583 int err = -1, ret;551 int err = -1, ret;
584 pid_t pid;552 pid_t pid;
585 struct map *map;553 struct map *map;
586 bool have_vmlinux, have_kcore, excl_kernel = false;554 bool have_vmlinux, have_kcore;
587 struct dso *dso;555 struct dso *dso;
556 const char *events[] = { "cycles", "cycles:u", "cpu-clock", "cpu-clock:u", NULL };
557 int evidx = 0;
588 558
589 pid = getpid();559 pid = getpid();
590 560
@@ -618,7 +588,7 @@ static int do_test_code_reading(bool try_kcore) · 27 unmodified lines
618 588
619 /* No point getting kernel events if there is no kernel object */589 /* No point getting kernel events if there is no kernel object */
620 if (!have_vmlinux && !have_kcore)590 if (!have_vmlinux && !have_kcore)
621 excl_kernel = true;591 evidx++;
622 592
623 threads = thread_map__new_by_tid(pid);593 threads = thread_map__new_by_tid(pid);
624 if (!threads) {594 if (!threads) {
@@ -640,13 +610,13 @@ static int do_test_code_reading(bool try_kcore) · 15 unmodified lines
640 goto out_put;610 goto out_put;
641 }611 }
642 612
643 cpus = perf_cpu_map__new(NULL);613 cpus = perf_cpu_map__new_online_cpus();
644 if (!cpus) {614 if (!cpus) {
645 pr_debug("perf_cpu_map__new failed\n");615 pr_debug("perf_cpu_map__new failed\n");
646 goto out_put;616 goto out_put;
647 }617 }
648 618
649 while (1) {619 while (events[evidx]) {
650 const char *str;620 const char *str;
651 621
652 evlist = evlist__new();622 evlist = evlist__new();
@@ -657,7 +627,7 @@ static int do_test_code_reading(bool try_kcore) · 4 unmodified lines
657 627
658 perf_evlist__set_maps(&evlist->core, cpus, threads);628 perf_evlist__set_maps(&evlist->core, cpus, threads);
659 629
660 str = do_determine_event(excl_kernel);630 str = events[evidx];
661 pr_debug("Parsing event '%s'\n", str);631 pr_debug("Parsing event '%s'\n", str);
662 ret = parse_event(evlist, str);632 ret = parse_event(evlist, str);
663 if (ret < 0) {633 if (ret < 0) {
@@ -675,32 +645,32 @@ static int do_test_code_reading(bool try_kcore) · 11 unmodified lines
675 645
676 ret = evlist__open(evlist);646 ret = evlist__open(evlist);
677 if (ret < 0) {647 if (ret < 0) {
678 if (!excl_kernel) {648 evidx++;
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 }
692 649
693 if (verbose > 0) {650 if (events[evidx] == NULL && verbose > 0) {
694 char errbuf[512];651 char errbuf[512];
695 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));652 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
696 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);653 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);
697 }654 }
698 655
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;
700 }667 }
701 break;668 break;
702 }669 }
703 670
671 if (events[evidx] == NULL)
672 goto out_put;
673
704 ret = evlist__mmap(evlist, UINT_MAX);674 ret = evlist__mmap(evlist, UINT_MAX);
705 if (ret < 0) {675 if (ret < 0) {
706 pr_debug("evlist__mmap failed\n");676 pr_debug("evlist__mmap failed\n");
@@ -721,7 +691,7 @@ static int do_test_code_reading(bool try_kcore) · 14 unmodified lines
721 err = TEST_CODE_READING_NO_KERNEL_OBJ;691 err = TEST_CODE_READING_NO_KERNEL_OBJ;
722 else if (!have_vmlinux && !try_kcore)692 else if (!have_vmlinux && !try_kcore)
723 err = TEST_CODE_READING_NO_VMLINUX;693 err = TEST_CODE_READING_NO_VMLINUX;
724 else if (excl_kernel)694 else if (strstr(events[evidx], ":u"))
725 err = TEST_CODE_READING_NO_ACCESS;695 err = TEST_CODE_READING_NO_ACCESS;
726 else696 else
727 err = TEST_CODE_READING_OK;697 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
213 213
214static int test__cpu_map_equal(struct test_suite *test __maybe_unused, int subtest __maybe_unused)214static int test__cpu_map_equal(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
215{215{
216 struct perf_cpu_map *any = perf_cpu_map__dummy_new();216 struct perf_cpu_map *any = perf_cpu_map__new_any_cpu();
217 struct perf_cpu_map *one = perf_cpu_map__new("1");217 struct perf_cpu_map *one = perf_cpu_map__new("1");
218 struct perf_cpu_map *two = perf_cpu_map__new("2");218 struct perf_cpu_map *two = perf_cpu_map__new("2");
219 struct perf_cpu_map *empty = perf_cpu_map__intersect(one, two);219 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
394 return 0;394 return 0;
395}395}
396 396
397DEFINE_SUITE("DSO data read", dso_data);397
398DEFINE_SUITE("DSO data cache", dso_data_cache);398static struct test_case tests__dso_data[] = {
399DEFINE_SUITE("DSO data reopen", dso_data_reopen);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
405struct 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
81 threads = thread_map__new(-1, getpid(), UINT_MAX);81 threads = thread_map__new(-1, getpid(), UINT_MAX);
82 CHECK_NOT_NULL__(threads);82 CHECK_NOT_NULL__(threads);
83 83
84 cpus = perf_cpu_map__new(NULL);84 cpus = perf_cpu_map__new_online_cpus();
85 CHECK_NOT_NULL__(cpus);85 CHECK_NOT_NULL__(cpus);
86 86
87 evlist = evlist__new();87 evlist = evlist__new();
tools/perf/tests/make+1−1
@@ -183,7 +183,7 @@ run += make_install_prefix_slash · 182 unmodified lines
183# run += make_install_pdf183# run += make_install_pdf
184run += make_minimal184run += make_minimal
185 185
186old_libbpf := $(shell echo '\#include <bpf/libbpf.h>' | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}")186old_libbpf := $(shell echo '\#include <bpf/libbpf.h>' | $(CC) -E -dM -x c -| grep -q -E "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}")
187 187
188ifneq ($(old_libbpf),)188ifneq ($(old_libbpf),)
189run += make_libbpf_dynamic189run += make_libbpf_dynamic
tools/perf/tests/maps.c+38−23
@@ -14,44 +14,59 @@ struct map_def { · 13 unmodified lines
14 u64 end;14 u64 end;
15};15};
16 16
17struct check_maps_cb_args {
18 struct map_def *merged;
19 unsigned int i;
20};
21
22static 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
37static 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
17static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps)48static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps)
18{49{
19 struct map_rb_node *rb_node;
20 unsigned int i = 0;
21 bool failed = false;50 bool failed = false;
22 51
23 if (maps__nr_maps(maps) != size) {52 if (maps__nr_maps(maps) != size) {
24 pr_debug("Expected %d maps, got %d", size, maps__nr_maps(maps));53 pr_debug("Expected %d maps, got %d", size, maps__nr_maps(maps));
25 failed = true;54 failed = true;
26 } else {55 } else {
27 maps__for_each_entry(maps, rb_node) {56 struct check_maps_cb_args args = {
28 struct map *map = rb_node->map;57 .merged = merged,
29 58 .i = 0,
30 if (map__start(map) != merged[i].start ||59 };
31 map__end(map) != merged[i].end ||60 failed = maps__for_each_map(maps, check_maps_cb, &args);
32 strcmp(map__dso(map)->name, merged[i].name) ||
33 refcount_read(map__refcnt(map)) != 1) {
34 failed = true;
35 }
36 i++;
37 }
38 }61 }
39 if (failed) {62 if (failed) {
40 pr_debug("Expected:\n");63 pr_debug("Expected:\n");
41 for (i = 0; i < size; i++) {64 for (unsigned int i = 0; i < size; i++) {
42 pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n",65 pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n",
43 merged[i].start, merged[i].end, merged[i].name);66 merged[i].start, merged[i].end, merged[i].name);
44 }67 }
45 pr_debug("Got:\n");68 pr_debug("Got:\n");
46 maps__for_each_entry(maps, rb_node) {69 maps__for_each_map(maps, failed_cb, NULL);
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 }
55 }70 }
56 return failed ? TEST_FAIL : TEST_OK;71 return failed ? TEST_FAIL : TEST_OK;
57}72}
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
52 return -1;52 return -1;
53 }53 }
54 54
55 cpus = perf_cpu_map__new(NULL);55 cpus = perf_cpu_map__new_online_cpus();
56 if (cpus == NULL) {56 if (cpus == NULL) {
57 pr_debug("perf_cpu_map__new\n");57 pr_debug("perf_cpu_map__new\n");
58 goto out_free_threads;58 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
37 return -1;37 return -1;
38 }38 }
39 39
40 cpus = perf_cpu_map__new(NULL);40 cpus = perf_cpu_map__new_online_cpus();
41 if (cpus == NULL) {41 if (cpus == NULL) {
42 pr_debug("perf_cpu_map__new\n");42 pr_debug("perf_cpu_map__new\n");
43 goto out_thread_map_delete;43 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
162 return TEST_OK;162 return TEST_OK;
163}163}
164 164
165
166static 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
165static int test__checkevent_symbolic_name(struct evlist *evlist)181static int test__checkevent_symbolic_name(struct evlist *evlist)
166{182{
167 struct perf_evsel *evsel;183 struct perf_evsel *evsel;
@@ -169,10 +185,12 @@ static int test__checkevent_symbolic_name(struct evlist *evlist) · 1 unmodified line
169 TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries);185 TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries);
170 186
171 perf_evlist__for_each_evsel(&evlist->core, evsel) {187 perf_evlist__for_each_evsel(&evlist->core, evsel) {
172 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);188 int ret = assert_hw(evsel, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
173 TEST_ASSERT_VAL("wrong config",189
174 test_perf_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));190 if (ret)
191 return ret;
175 }192 }
193
176 return TEST_OK;194 return TEST_OK;
177}195}
178 196
@@ -183,8 +201,10 @@ static int test__checkevent_symbolic_name_config(struct evlist *evlist) · 4 unmodified lines
183 TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries);201 TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries);
184 202
185 perf_evlist__for_each_evsel(&evlist->core, evsel) {203 perf_evlist__for_each_evsel(&evlist->core, evsel) {
186 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);204 int ret = assert_hw(evsel, PERF_COUNT_HW_CPU_CYCLES, "cycles");
187 TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, PERF_COUNT_HW_CPU_CYCLES));205
206 if (ret)
207 return ret;
188 /*208 /*
189 * The period value gets configured within evlist__config,209 * The period value gets configured within evlist__config,
190 * while this test executes only parse events method.210 * while this test executes only parse events method.
@@ -861,10 +881,14 @@ static int test__group1(struct evlist *evlist) · 670 unmodified lines
861 evlist__nr_groups(evlist) == num_core_entries());881 evlist__nr_groups(evlist) == num_core_entries());
862 882
863 for (int i = 0; i < num_core_entries(); i++) {883 for (int i = 0; i < num_core_entries(); i++) {
884 int ret;
885
864 /* instructions:k */886 /* instructions:k */
865 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));887 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
866 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);888 ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
867 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));889 if (ret)
890 return ret;
891
868 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);892 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
869 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);893 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
870 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);894 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
878 902
879 /* cycles:upp */903 /* cycles:upp */
880 evsel = evsel__next(evsel);904 evsel = evsel__next(evsel);
881 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);905 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
882 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));906 if (ret)
907 return ret;
908
883 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);909 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
884 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);910 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
885 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);911 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
907 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist));933 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist));
908 934
909 evlist__for_each_entry(evlist, evsel) {935 evlist__for_each_entry(evlist, evsel) {
936 int ret;
937
910 if (evsel->core.attr.type == PERF_TYPE_SOFTWARE) {938 if (evsel->core.attr.type == PERF_TYPE_SOFTWARE) {
911 /* faults + :ku modifier */939 /* faults + :ku modifier */
912 leader = evsel;940 leader = evsel;
@@ -939,8 +967,10 @@ static int test__group2(struct evlist *evlist) · 26 unmodified lines
939 continue;967 continue;
940 }968 }
941 /* cycles:k */969 /* cycles:k */
942 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);970 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
943 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));971 if (ret)
972 return ret;
973
944 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);974 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
945 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);975 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
946 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);976 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
957static int test__group3(struct evlist *evlist __maybe_unused)987static int test__group3(struct evlist *evlist __maybe_unused)
958{988{
959 struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL;989 struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL;
990 int ret;
960 991
961 TEST_ASSERT_VAL("wrong number of entries",992 TEST_ASSERT_VAL("wrong number of entries",
962 evlist->core.nr_entries == (3 * perf_pmus__num_core_pmus() + 2));993 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
1045 continue;1076 continue;
1046 }1077 }
1047 /* instructions:u */1078 /* instructions:u */
1048 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1079 ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1049 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));1080 if (ret)
1081 return ret;
1082
1050 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1083 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1051 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1084 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1052 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1085 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
1070 num_core_entries() == evlist__nr_groups(evlist));1103 num_core_entries() == evlist__nr_groups(evlist));
1071 1104
1072 for (int i = 0; i < num_core_entries(); i++) {1105 for (int i = 0; i < num_core_entries(); i++) {
1106 int ret;
1107
1073 /* cycles:u + p */1108 /* cycles:u + p */
1074 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1109 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1075 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1110 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1076 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1111 if (ret)
1112 return ret;
1113
1077 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1114 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1078 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1115 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1079 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1116 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
1089 1126
1090 /* instructions:kp + p */1127 /* instructions:kp + p */
1091 evsel = evsel__next(evsel);1128 evsel = evsel__next(evsel);
1092 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1129 ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1093 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));1130 if (ret)
1131 return ret;
1132
1094 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);1133 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
1095 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1134 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1096 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1135 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
1108static int test__group5(struct evlist *evlist __maybe_unused)1147static int test__group5(struct evlist *evlist __maybe_unused)
1109{1148{
1110 struct evsel *evsel = NULL, *leader;1149 struct evsel *evsel = NULL, *leader;
1150 int ret;
1111 1151
1112 TEST_ASSERT_VAL("wrong number of entries",1152 TEST_ASSERT_VAL("wrong number of entries",
1113 evlist->core.nr_entries == (5 * num_core_entries()));1153 evlist->core.nr_entries == (5 * num_core_entries()));
@@ -1117,8 +1157,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) · 3 unmodified lines
1117 for (int i = 0; i < num_core_entries(); i++) {1157 for (int i = 0; i < num_core_entries(); i++) {
1118 /* cycles + G */1158 /* cycles + G */
1119 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1159 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1120 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1160 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1121 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1161 if (ret)
1162 return ret;
1163
1122 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1164 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1123 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1165 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1124 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1166 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
1133 1175
1134 /* instructions + G */1176 /* instructions + G */
1135 evsel = evsel__next(evsel);1177 evsel = evsel__next(evsel);
1136 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1178 ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1137 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));1179 if (ret)
1180 return ret;
1181
1138 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1182 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1139 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1183 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1140 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1184 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
1148 for (int i = 0; i < num_core_entries(); i++) {1192 for (int i = 0; i < num_core_entries(); i++) {
1149 /* cycles:G */1193 /* cycles:G */
1150 evsel = leader = evsel__next(evsel);1194 evsel = leader = evsel__next(evsel);
1151 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1195 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1152 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1196 if (ret)
1197 return ret;
1198
1153 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1199 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1154 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1200 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1155 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1201 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
1164 1210
1165 /* instructions:G */1211 /* instructions:G */
1166 evsel = evsel__next(evsel);1212 evsel = evsel__next(evsel);
1167 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1213 ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1168 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));1214 if (ret)
1215 return ret;
1216
1169 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1217 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1170 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1218 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1171 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1219 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
1178 for (int i = 0; i < num_core_entries(); i++) {1226 for (int i = 0; i < num_core_entries(); i++) {
1179 /* cycles */1227 /* cycles */
1180 evsel = evsel__next(evsel);1228 evsel = evsel__next(evsel);
1181 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1229 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1182 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1230 if (ret)
1231 return ret;
1232
1183 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1233 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1184 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1234 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1185 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1235 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
1201 evlist__nr_groups(evlist) == num_core_entries());1251 evlist__nr_groups(evlist) == num_core_entries());
1202 1252
1203 for (int i = 0; i < num_core_entries(); i++) {1253 for (int i = 0; i < num_core_entries(); i++) {
1254 int ret;
1255
1204 /* cycles + :H group modifier */1256 /* cycles + :H group modifier */
1205 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1257 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1206 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1258 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1207 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1259 if (ret)
1260 return ret;
1261
1208 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1262 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1209 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1263 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1210 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1264 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
1218 1272
1219 /* cache-misses:G + :H group modifier */1273 /* cache-misses:G + :H group modifier */
1220 evsel = evsel__next(evsel);1274 evsel = evsel__next(evsel);
1221 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1275 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1222 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1276 if (ret)
1277 return ret;
1278
1223 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1279 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1224 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1280 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1225 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1281 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
1242 evlist__nr_groups(evlist) == num_core_entries());1298 evlist__nr_groups(evlist) == num_core_entries());
1243 1299
1244 for (int i = 0; i < num_core_entries(); i++) {1300 for (int i = 0; i < num_core_entries(); i++) {
1301 int ret;
1302
1245 /* cycles + :G group modifier */1303 /* cycles + :G group modifier */
1246 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1304 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1247 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1305 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1248 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1306 if (ret)
1307 return ret;
1308
1249 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1309 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1250 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1310 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1251 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1311 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
1259 1319
1260 /* cache-misses:H + :G group modifier */1320 /* cache-misses:H + :G group modifier */
1261 evsel = evsel__next(evsel);1321 evsel = evsel__next(evsel);
1262 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1322 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1263 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1323 if (ret)
1324 return ret;
1325
1264 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1326 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1265 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1327 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1266 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1328 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
1283 evlist__nr_groups(evlist) == num_core_entries());1345 evlist__nr_groups(evlist) == num_core_entries());
1284 1346
1285 for (int i = 0; i < num_core_entries(); i++) {1347 for (int i = 0; i < num_core_entries(); i++) {
1348 int ret;
1349
1286 /* cycles:G + :u group modifier */1350 /* cycles:G + :u group modifier */
1287 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1351 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1288 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1352 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1289 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1353 if (ret)
1354 return ret;
1355
1290 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1356 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1291 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1357 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1292 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1358 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
1300 1366
1301 /* cache-misses:H + :u group modifier */1367 /* cache-misses:H + :u group modifier */
1302 evsel = evsel__next(evsel);1368 evsel = evsel__next(evsel);
1303 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1369 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1304 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1370 if (ret)
1371 return ret;
1372
1305 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1373 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1306 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1374 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1307 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1375 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
1324 evlist__nr_groups(evlist) == num_core_entries());1392 evlist__nr_groups(evlist) == num_core_entries());
1325 1393
1326 for (int i = 0; i < num_core_entries(); i++) {1394 for (int i = 0; i < num_core_entries(); i++) {
1395 int ret;
1396
1327 /* cycles:G + :uG group modifier */1397 /* cycles:G + :uG group modifier */
1328 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1398 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1329 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1399 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1330 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1400 if (ret)
1401 return ret;
1402
1331 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1403 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1332 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1404 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1333 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1405 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
1341 1413
1342 /* cache-misses:H + :uG group modifier */1414 /* cache-misses:H + :uG group modifier */
1343 evsel = evsel__next(evsel);1415 evsel = evsel__next(evsel);
1344 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1416 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1345 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1417 if (ret)
1418 return ret;
1419
1346 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1420 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1347 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1421 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1348 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1422 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
1363 evlist->core.nr_entries == (3 * num_core_entries()));1437 evlist->core.nr_entries == (3 * num_core_entries()));
1364 1438
1365 for (int i = 0; i < num_core_entries(); i++) {1439 for (int i = 0; i < num_core_entries(); i++) {
1440 int ret;
1441
1366 /* cycles - sampling group leader */1442 /* cycles - sampling group leader */
1367 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1443 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1368 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1444 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1369 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1445 if (ret)
1446 return ret;
1447
1370 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1448 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1371 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1449 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1372 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1450 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
1379 1457
1380 /* cache-misses - not sampling */1458 /* cache-misses - not sampling */
1381 evsel = evsel__next(evsel);1459 evsel = evsel__next(evsel);
1382 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1460 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1383 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1461 if (ret)
1462 return ret;
1463
1384 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1464 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1385 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1465 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1386 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1466 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
1392 1472
1393 /* branch-misses - not sampling */1473 /* branch-misses - not sampling */
1394 evsel = evsel__next(evsel);1474 evsel = evsel__next(evsel);
1395 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1475 ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses");
1396 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES));1476 if (ret)
1477 return ret;
1478
1397 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1479 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1398 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);1480 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
1399 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);1481 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
1415 evlist->core.nr_entries == (2 * num_core_entries()));1497 evlist->core.nr_entries == (2 * num_core_entries()));
1416 1498
1417 for (int i = 0; i < num_core_entries(); i++) {1499 for (int i = 0; i < num_core_entries(); i++) {
1500 int ret;
1501
1418 /* instructions - sampling group leader */1502 /* instructions - sampling group leader */
1419 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1503 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1420 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1504 ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1421 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));1505 if (ret)
1506 return ret;
1507
1422 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1508 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1423 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1509 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1424 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1510 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
1431 1517
1432 /* branch-misses - not sampling */1518 /* branch-misses - not sampling */
1433 evsel = evsel__next(evsel);1519 evsel = evsel__next(evsel);
1434 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1520 ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses");
1435 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES));1521 if (ret)
1522 return ret;
1523
1436 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);1524 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
1437 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1525 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1438 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);1526 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
1472 evlist->core.nr_entries == (3 * num_core_entries()));1560 evlist->core.nr_entries == (3 * num_core_entries()));
1473 1561
1474 for (int i = 0; i < num_core_entries(); i++) {1562 for (int i = 0; i < num_core_entries(); i++) {
1563 int ret;
1564
1475 /* cycles - group leader */1565 /* cycles - group leader */
1476 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1566 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1477 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1567 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1478 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1568 if (ret)
1569 return ret;
1570
1479 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);1571 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1480 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));1572 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
1481 /* TODO: The group modifier is not copied to the split group leader. */1573 /* 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
1484 1576
1485 /* cache-misses - can not be pinned, but will go on with the leader */1577 /* cache-misses - can not be pinned, but will go on with the leader */
1486 evsel = evsel__next(evsel);1578 evsel = evsel__next(evsel);
1487 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1579 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1488 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1580 if (ret)
1581 return ret;
1582
1489 TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);1583 TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);
1490 1584
1491 /* branch-misses - ditto */1585 /* branch-misses - ditto */
1492 evsel = evsel__next(evsel);1586 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
1494 TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);1591 TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);
1495 }1592 }
1496 return TEST_OK;1593 return TEST_OK;
@@ -1517,10 +1614,14 @@ static int test__exclusive_group(struct evlist *evlist) · 20 unmodified lines
1517 evlist->core.nr_entries == 3 * num_core_entries());1614 evlist->core.nr_entries == 3 * num_core_entries());
1518 1615
1519 for (int i = 0; i < num_core_entries(); i++) {1616 for (int i = 0; i < num_core_entries(); i++) {
1617 int ret;
1618
1520 /* cycles - group leader */1619 /* cycles - group leader */
1521 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));1620 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1522 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1621 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1523 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));1622 if (ret)
1623 return ret;
1624
1524 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);1625 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
1525 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));1626 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
1526 /* TODO: The group modifier is not copied to the split group leader. */1627 /* 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
1529 1630
1530 /* cache-misses - can not be pinned, but will go on with the leader */1631 /* cache-misses - can not be pinned, but will go on with the leader */
1531 evsel = evsel__next(evsel);1632 evsel = evsel__next(evsel);
1532 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);1633 ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1533 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));1634 if (ret)
1635 return ret;
1636
1534 TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);1637 TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);
1535 1638
1536 /* branch-misses - ditto */1639 /* branch-misses - ditto */
1537 evsel = evsel__next(evsel);1640 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
1539 TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);1645 TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);
1540 }1646 }
1541 return TEST_OK;1647 return TEST_OK;
@@ -1677,9 +1783,11 @@ static int test__checkevent_raw_pmu(struct evlist *evlist) · 135 unmodified lines
1677static int test__sym_event_slash(struct evlist *evlist)1783static int test__sym_event_slash(struct evlist *evlist)
1678{1784{
1679 struct evsel *evsel = evlist__first(evlist);1785 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;
1680 1790
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));
1683 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);1791 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
1684 return TEST_OK;1792 return TEST_OK;
1685}1793}
@@ -1687,9 +1795,11 @@ static int test__sym_event_slash(struct evlist *evlist) · 1 unmodified line
1687static int test__sym_event_dc(struct evlist *evlist)1795static int test__sym_event_dc(struct evlist *evlist)
1688{1796{
1689 struct evsel *evsel = evlist__first(evlist);1797 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;
1690 1802
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));
1693 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);1803 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
1694 return TEST_OK;1804 return TEST_OK;
1695}1805}
@@ -1697,9 +1807,11 @@ static int test__sym_event_dc(struct evlist *evlist) · 1 unmodified line
1697static int test__term_equal_term(struct evlist *evlist)1807static int test__term_equal_term(struct evlist *evlist)
1698{1808{
1699 struct evsel *evsel = evlist__first(evlist);1809 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;
1700 1814
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));
1703 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "name") == 0);1815 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "name") == 0);
1704 return TEST_OK;1816 return TEST_OK;
1705}1817}
@@ -1707,9 +1819,11 @@ static int test__term_equal_term(struct evlist *evlist) · 1 unmodified line
1707static int test__term_equal_legacy(struct evlist *evlist)1819static int test__term_equal_legacy(struct evlist *evlist)
1708{1820{
1709 struct evsel *evsel = evlist__first(evlist);1821 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;
1710 1826
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));
1713 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "l1d") == 0);1827 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "l1d") == 0);
1714 return TEST_OK;1828 return TEST_OK;
1715}1829}
@@ -2549,7 +2663,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest · 833 unmodified lines
2549 if (strchr(ent->d_name, '.'))2663 if (strchr(ent->d_name, '.'))
2550 continue;2664 continue;
2551 2665
2552 /* exclude parametrized ones (name contains '?') */2666 /* exclude parameterized ones (name contains '?') */
2553 n = snprintf(pmu_event, sizeof(pmu_event), "%s%s", path, ent->d_name);2667 n = snprintf(pmu_event, sizeof(pmu_event), "%s%s", path, ent->d_name);
2554 if (n >= PATH_MAX) {2668 if (n >= PATH_MAX) {
2555 pr_err("pmu event name crossed PATH_MAX(%d) size\n", PATH_MAX);2669 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
2578 fclose(file);2692 fclose(file);
2579 2693
2580 if (is_event_parameterized == 1) {2694 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);
2582 continue;2696 continue;
2583 }2697 }
2584 2698
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
93 threads = thread_map__new(-1, getpid(), UINT_MAX);93 threads = thread_map__new(-1, getpid(), UINT_MAX);
94 CHECK_NOT_NULL__(threads);94 CHECK_NOT_NULL__(threads);
95 95
96 cpus = perf_cpu_map__new(NULL);96 cpus = perf_cpu_map__new_online_cpus();
97 CHECK_NOT_NULL__(cpus);97 CHECK_NOT_NULL__(cpus);
98 98
99 evlist = evlist__new();99 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
42int main(int argc, char **argv)42int main(int argc, char **argv)
43{43{
44 unsigned long i, len, size, thr;44 unsigned long i, len, size, thr;
45 pthread_t threads[256];
46 struct args args[256];45 struct args args[256];
47 long long v;46 long long v;
48 47
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
57int main(int argc, char **argv)57int main(int argc, char **argv)
58{58{
59 unsigned int i, len, thr;59 unsigned int i, len, thr;
60 pthread_t threads[256];
61 struct args args[256];60 struct args args[256];
62 61
63 if (argc < 3) {62 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
51int main(int argc, char **argv)51int main(int argc, char **argv)
52{52{
53 unsigned int i, thr;53 unsigned int i, thr;
54 pthread_t threads[256];
55 struct args args[256];54 struct args args[256];
56 55
57 if (argc < 2) {56 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
5set -e
6
7err=0
8perfdata1=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
9perfdata2=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
10perfdata3=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
11testprog="perf test -w thloop"
12
13shelldir=$(dirname "$0")
14# shellcheck source=lib/perf_has_symbol.sh
15. "${shelldir}"/lib/perf_has_symbol.sh
16
17testsym="test_loop"
18
19skip_test_missing_symbol ${testsym}
20
21cleanup() {
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
32trap_cleanup() {
33 cleanup
34 exit 1
35}
36trap trap_cleanup EXIT TERM INT
37
38make_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
55test_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
77test_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
104test_two_files
105test_three_files
106
107cleanup
108exit $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
4perf_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
14skip_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
4if [ "x$PYTHON" = "x" ]
5then
6 python3 --version >/dev/null 2>&1 && PYTHON=python3
7fi
8if [ "x$PYTHON" = "x" ]
9then
10 python --version >/dev/null 2>&1 && PYTHON=python
11fi
12if [ "x$PYTHON" = "x" ]
13then
14 echo Skipping test, python not detected please set environment variable PYTHON.
15 exit 2
16fi
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
5set -e
6err=0
7
8shelldir=$(dirname "$0")
9# shellcheck source=lib/setup_python.sh
10. "${shelldir}"/lib/setup_python.sh
11
12test_list_json() {
13 echo "Json output test"
14 perf list -j | $PYTHON -m json.tool
15 echo "Json output test [Success]"
16}
17
18test_list_json
19exit $err
tools/perf/tests/shell/pipe_test.sh+8−1
@@ -2,10 +2,17 @@ · 1 unmodified line
2# perf pipe recording and injection test2# perf pipe recording and injection test
3# SPDX-License-Identifier: GPL-2.03# SPDX-License-Identifier: GPL-2.0
4 4
5shelldir=$(dirname "$0")
6# shellcheck source=lib/perf_has_symbol.sh
7. "${shelldir}"/lib/perf_has_symbol.sh
8
9sym="noploop"
10
11skip_test_missing_symbol ${sym}
12
5data=$(mktemp /tmp/perf.data.XXXXXX)13data=$(mktemp /tmp/perf.data.XXXXXX)
6prog="perf test -w noploop"14prog="perf test -w noploop"
7task="perf"15task="perf"
8sym="noploop"
9 16
10if ! perf record -e task-clock:u -o - ${prog} | perf report -i - --task | grep ${task}; then17if ! perf record -e task-clock:u -o - ${prog} | perf report -i - --task | grep ${task}; then
11 echo "cannot find the test file in the perf report"18 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
45 ;;45 ;;
46 ppc64|ppc64le)46 ppc64|ppc64le)
47 eventattr='max-stack=4'47 eventattr='max-stack=4'
48 echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected48 # 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
49 echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected52 echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
50 echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected53 echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected
51 ;;54 ;;
tools/perf/tests/shell/record.sh+37−1
@@ -8,10 +8,19 @@ shelldir=$(dirname "$0") · 7 unmodified lines
8# shellcheck source=lib/waiting.sh8# shellcheck source=lib/waiting.sh
9. "${shelldir}"/lib/waiting.sh9. "${shelldir}"/lib/waiting.sh
10 10
11# shellcheck source=lib/perf_has_symbol.sh
12. "${shelldir}"/lib/perf_has_symbol.sh
13
14testsym="test_loop"
15
16skip_test_missing_symbol ${testsym}
17
11err=018err=0
12perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)19perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
13testprog="perf test -w thloop"20testprog="perf test -w thloop"
14testsym="test_loop"21cpu_pmu_dir="/sys/bus/event_source/devices/cpu*"
22br_cntr_file="/caps/branch_counter_nr"
23br_cntr_output="branch stack counters"
15 24
16cleanup() {25cleanup() {
17 rm -rf "${perfdata}"26 rm -rf "${perfdata}"
@@ -155,10 +164,37 @@ test_workload() { · 137 unmodified lines
155 echo "Basic target workload test [Success]"164 echo "Basic target workload test [Success]"
156}165}
157 166
167test_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
158test_per_thread193test_per_thread
159test_register_capture194test_register_capture
160test_system_wide195test_system_wide
161test_workload196test_workload
197test_branch_counter
162 198
163cleanup199cleanup
164exit $err200exit $err
tools/perf/tests/shell/record_offcpu.sh+2−2
@@ -77,9 +77,9 @@ test_offcpu_child() { · 76 unmodified lines
77 err=177 err=1
78 return78 return
79 fi79 fi
80 # each process waits for read and write, so it should be more than 800 events80 # each process waits at least for poll, so it should be more than 400 events
81 if ! perf report -i ${perfdata} -s comm -q -n -t ';' --percent-limit=90 | \81 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; }'
83 then83 then
84 echo "Child task off-cpu test [Failed invalid output]"84 echo "Child task off-cpu test [Failed invalid output]"
85 err=185 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
5set -e
6
7temp_dir=$(mktemp -d /tmp/perf-test-script.XXXXXXXXXX)
8
9perfdatafile="${temp_dir}/perf.data"
10db_test="${temp_dir}/db_test.py"
11
12err=0
13
14cleanup()
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
25trap_cleanup()
26{
27 cleanup
28 exit 1
29}
30
31trap trap_cleanup EXIT TERM INT
32
33
34test_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}"
47perf_db_export_mode = True
48perf_db_export_calls = False
49perf_db_export_callchains = True
50
51def sample_table(*args):
52 print(f'sample_table({args})')
53
54def 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
62test_db
63
64cleanup
65
66exit $err
tools/perf/tests/shell/stat+json_output.sh+3−13
@@ -8,20 +8,10 @@ set -e · 7 unmodified lines
8 8
9skip_test=09skip_test=0
10 10
11shelldir=$(dirname "$0")
12# shellcheck source=lib/setup_python.sh
13. "${shelldir}"/lib/setup_python.sh
11pythonchecker=$(dirname $0)/lib/perf_json_output_lint.py14pythonchecker=$(dirname $0)/lib/perf_json_output_lint.py
12if [ "x$PYTHON" == "x" ]
13then
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
24fi
25 15
26stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX)16stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX)
27 17
tools/perf/tests/shell/stat_all_pmu.sh+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
4 4
5set -e5set -e
6 6
7# Test all PMU events; however exclude parametrized ones (name contains '?')7# Test all PMU events; however exclude parameterized ones (name contains '?')
8for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g'); do8for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g'); do
9 echo "Testing $p"9 echo "Testing $p"
10 result=$(perf stat -e "$p" true 2>&1)10 result=$(perf stat -e "$p" true 2>&1)
tools/perf/tests/shell/stat_metrics_values.sh+4−10
@@ -1,16 +1,10 @@
1#!/bin/bash1#!/bin/bash
2# perf metrics value validation2# perf metrics value validation
3# SPDX-License-Identifier: GPL-2.03# SPDX-License-Identifier: GPL-2.0
4if [ "x$PYTHON" == "x" ]4
5then5shelldir=$(dirname "$0")
6 if which python3 > /dev/null6# shellcheck source=lib/setup_python.sh
7 then7. "${shelldir}"/lib/setup_python.sh
8 PYTHON=python3
9 else
10 echo Skipping test, python3 not detected please set environment variable PYTHON.
11 exit 2
12 fi
13fi
14 8
15grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; }9grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; }
16 10
tools/perf/tests/shell/test_arm_callgraph_fp.sh+6−0
@@ -2,8 +2,14 @@ · 1 unmodified line
2# Check Arm64 callgraphs are complete in fp mode2# Check Arm64 callgraphs are complete in fp mode
3# SPDX-License-Identifier: GPL-2.03# SPDX-License-Identifier: GPL-2.0
4 4
5shelldir=$(dirname "$0")
6# shellcheck source=lib/perf_has_symbol.sh
7. "${shelldir}"/lib/perf_has_symbol.sh
8
5lscpu | grep -q "aarch64" || exit 29lscpu | grep -q "aarch64" || exit 2
6 10
11skip_test_missing_symbol leafloop
12
7PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX)13PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
8TEST_PROGRAM="perf test -w leafloop"14TEST_PROGRAM="perf test -w leafloop"
9 15
tools/perf/tests/shell/test_brstack.sh+6−0
@@ -4,6 +4,10 @@ · 3 unmodified lines
4# SPDX-License-Identifier: GPL-2.04# SPDX-License-Identifier: GPL-2.0
5# German Gomez <german.gomez@arm.com>, 20225# German Gomez <german.gomez@arm.com>, 2022
6 6
7shelldir=$(dirname "$0")
8# shellcheck source=lib/perf_has_symbol.sh
9. "${shelldir}"/lib/perf_has_symbol.sh
10
7# skip the test if the hardware doesn't support branch stack sampling11# skip the test if the hardware doesn't support branch stack sampling
8# and if the architecture doesn't support filter types: any,save_type,u12# and if the architecture doesn't support filter types: any,save_type,u
9if ! perf record -o- --no-buildid --branch-filter any,save_type,u -- true > /dev/null 2>&1 ; then13if ! 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
11 exit 215 exit 2
12fi16fi
13 17
18skip_test_missing_symbol brstack_bench
19
14TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX)20TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX)
15TESTPROG="perf test -w brstack"21TESTPROG="perf test -w brstack"
16 22
tools/perf/tests/shell/test_data_symbol.sh+14−2
@@ -4,6 +4,13 @@ · 3 unmodified lines
4# SPDX-License-Identifier: GPL-2.04# SPDX-License-Identifier: GPL-2.0
5# Leo Yan <leo.yan@linaro.org>, 20225# Leo Yan <leo.yan@linaro.org>, 2022
6 6
7shelldir=$(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
7skip_if_no_mem_event() {14skip_if_no_mem_event() {
8 perf mem record -e list 2>&1 | grep -E -q 'available' && return 015 perf mem record -e list 2>&1 | grep -E -q 'available' && return 0
9 return 216 return 2
@@ -11,8 +18,11 @@ skip_if_no_mem_event() { · 1 unmodified line
11 18
12skip_if_no_mem_event || exit 219skip_if_no_mem_event || exit 2
13 20
21skip_test_missing_symbol buf1
22
14TEST_PROGRAM="perf test -w datasym"23TEST_PROGRAM="perf test -w datasym"
15PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX)24PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
25ERR_FILE=$(mktemp /tmp/__perf_test.stderr.XXXXX)
16 26
17check_result() {27check_result() {
18 # The memory report format is as below:28 # The memory report format is as below:
@@ -50,13 +60,15 @@ echo "Recording workload..." · 31 unmodified lines
50# specific CPU and test in per-CPU mode.60# specific CPU and test in per-CPU mode.
51is_amd=$(grep -E -c 'vendor_id.*AuthenticAMD' /proc/cpuinfo)61is_amd=$(grep -E -c 'vendor_id.*AuthenticAMD' /proc/cpuinfo)
52if (($is_amd >= 1)); then62if (($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}" &
54else64else
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}" &
56fi66fi
57 67
58PERFPID=$!68PERFPID=$!
59 69
70wait_for_perf_to_start ${PERFPID} "${ERR_FILE}"
71
60sleep 172sleep 1
61 73
62kill $PERFPID74kill $PERFPID
tools/perf/tests/shell/test_perf_data_converter_json.sh+3−10
@@ -6,16 +6,9 @@ set -e · 5 unmodified lines
6 6
7err=07err=0
8 8
9if [ "$PYTHON" = "" ] ; then9shelldir=$(dirname "$0")
10 if which python3 > /dev/null ; then10# shellcheck source=lib/setup_python.sh
11 PYTHON=python311. "${shelldir}"/lib/setup_python.sh
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
18fi
19 12
20perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)13perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
21result=$(mktemp /tmp/__perf_test.output.json.XXXXX)14result=$(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
57#ifdef HAVE_BPF_SKEL57#ifdef HAVE_BPF_SKEL
58#include <bpf/btf.h>58#include <bpf/btf.h>
59 59
60static bool attr_has_sigtrap(void)60static struct btf *btf;
61
62static bool btf__available(void)
61{63{
62 bool ret = false;64 if (btf == NULL)
63 struct btf *btf;65 btf = btf__load_vmlinux_btf();
64 const struct btf_type *t;66
67 return btf != NULL;
68}
69
70static void btf__exit(void)
71{
72 btf__free(btf);
73 btf = NULL;
74}
75
76static 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);
65 const struct btf_member *m;79 const struct btf_member *m;
66 const char *name;80 int i;
67 int i, id;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 }
68 87
69 btf = btf__load_vmlinux_btf();88 return NULL;
70 if (btf == NULL) {89}
90
91static bool attr_has_sigtrap(void)
92{
93 int id;
94
95 if (!btf__available()) {
71 /* should be an old kernel */96 /* should be an old kernel */
72 return false;97 return false;
73 }98 }
74 99
75 id = btf__find_by_name_kind(btf, "perf_event_attr", BTF_KIND_STRUCT);100 id = btf__find_by_name_kind(btf, "perf_event_attr", BTF_KIND_STRUCT);
76 if (id < 0)101 if (id < 0)
77 goto out;102 return false;
78 103
79 t = btf__type_by_id(btf, id);104 return __btf_type__find_member_by_name(id, "sigtrap") != NULL;
80 for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) {105}
81 name = btf__name_by_offset(btf, m->name_off);106
82 if (!strcmp(name, "sigtrap")) {107static bool kernel_with_sleepable_spinlocks(void)
83 ret = true;108{
84 break;109 const struct btf_member *member;
85 }110 const struct btf_type *type;
86 }111 const char *type_name;
87out:112 int id;
88 btf__free(btf);113
89 return ret;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");
90}133}
91#else /* !HAVE_BPF_SKEL */134#else /* !HAVE_BPF_SKEL */
92static bool attr_has_sigtrap(void)135static bool attr_has_sigtrap(void)
@@ -109,6 +152,15 @@ static bool attr_has_sigtrap(void) · 16 unmodified lines
109 152
110 return ret;153 return ret;
111}154}
155
156static bool kernel_with_sleepable_spinlocks(void)
157{
158 return false;
159}
160
161static void btf__exit(void)
162{
163}
112#endif /* HAVE_BPF_SKEL */164#endif /* HAVE_BPF_SKEL */
113 165
114static void166static void
@@ -147,7 +199,7 @@ static int run_test_threads(pthread_t *threads, pthread_barrier_t *barrier) · 32 unmodified lines
147 199
148static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrier)200static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrier)
149{201{
150 int ret;202 int ret, expected_sigtraps;
151 203
152 ctx.iterate_on = 3000;204 ctx.iterate_on = 3000;
153 205
@@ -156,7 +208,16 @@ static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrie · 2 unmodified lines
156 ret = run_test_threads(threads, barrier);208 ret = run_test_threads(threads, barrier);
157 TEST_ASSERT_EQUAL("disable failed", ioctl(fd, PERF_EVENT_IOC_DISABLE, 0), 0);209 TEST_ASSERT_EQUAL("disable failed", ioctl(fd, PERF_EVENT_IOC_DISABLE, 0), 0);
158 210
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
160 TEST_ASSERT_EQUAL("missing signals or incorrectly delivered", ctx.tids_want_signal, 0);221 TEST_ASSERT_EQUAL("missing signals or incorrectly delivered", ctx.tids_want_signal, 0);
161 TEST_ASSERT_VAL("unexpected si_addr", ctx.first_siginfo.si_addr == &ctx.iterate_on);222 TEST_ASSERT_VAL("unexpected si_addr", ctx.first_siginfo.si_addr == &ctx.iterate_on);
162#if 0 /* FIXME: enable when libc's signal.h has si_perf_{type,data} */223#if 0 /* FIXME: enable when libc's signal.h has si_perf_{type,data} */
@@ -221,6 +282,7 @@ out_restore_sigaction: · 58 unmodified lines
221 sigaction(SIGTRAP, &oldact, NULL);282 sigaction(SIGTRAP, &oldact, NULL);
222out:283out:
223 pthread_barrier_destroy(&barrier);284 pthread_barrier_destroy(&barrier);
285 btf__exit();
224 return ret;286 return ret;
225}287}
226 288
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
62 }62 }
63 evlist__add(evlist, evsel);63 evlist__add(evlist, evsel);
64 64
65 cpus = perf_cpu_map__dummy_new();65 cpus = perf_cpu_map__new_any_cpu();
66 threads = thread_map__new_by_tid(getpid());66 threads = thread_map__new_by_tid(getpid());
67 if (!cpus || !threads) {67 if (!cpus || !threads) {
68 err = -ENOMEM;68 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
351 goto out_err;351 goto out_err;
352 }352 }
353 353
354 cpus = perf_cpu_map__new(NULL);354 cpus = perf_cpu_map__new_online_cpus();
355 if (!cpus) {355 if (!cpus) {
356 pr_debug("perf_cpu_map__new failed!\n");356 pr_debug("perf_cpu_map__new failed!\n");
357 goto out_err;357 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
70 * evlist__prepare_workload we'll fill in the only thread70 * evlist__prepare_workload we'll fill in the only thread
71 * we're monitoring, the one forked there.71 * we're monitoring, the one forked there.
72 */72 */
73 cpus = perf_cpu_map__dummy_new();73 cpus = perf_cpu_map__new_any_cpu();
74 threads = thread_map__new_by_tid(-1);74 threads = thread_map__new_by_tid(-1);
75 if (!cpus || !threads) {75 if (!cpus || !threads) {
76 err = -ENOMEM;76 err = -ENOMEM;
tools/perf/tests/tests.h+1−0
@@ -207,5 +207,6 @@ DECLARE_WORKLOAD(brstack); · 206 unmodified lines
207DECLARE_WORKLOAD(datasym);207DECLARE_WORKLOAD(datasym);
208 208
209extern const char *dso_to_test;209extern const char *dso_to_test;
210extern const char *test_objdump_path;
210 211
211#endif /* TESTS_H */212#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
215 if (session_write_header(path))215 if (session_write_header(path))
216 goto free_path;216 goto free_path;
217 217
218 map = perf_cpu_map__new(NULL);218 map = perf_cpu_map__new_online_cpus();
219 if (map == NULL) {219 if (map == NULL) {
220 pr_debug("failed to get system cpumap\n");220 pr_debug("failed to get system cpumap\n");
221 goto free_path;221 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
112 return false;112 return false;
113}113}
114 114
115struct test__vmlinux_matches_kallsyms_cb_args {
116 struct machine kallsyms;
117 struct map *vmlinux_map;
118 bool header_printed;
119};
120
121static 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
146static 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
176static 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
115static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused,190static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused,
116 int subtest __maybe_unused)191 int subtest __maybe_unused)
117{192{
118 int err = TEST_FAIL;193 int err = TEST_FAIL;
119 struct rb_node *nd;194 struct rb_node *nd;
120 struct symbol *sym;195 struct symbol *sym;
121 struct map *kallsyms_map, *vmlinux_map;196 struct map *kallsyms_map;
122 struct map_rb_node *rb_node;197 struct machine vmlinux;
123 struct machine kallsyms, vmlinux;
124 struct maps *maps;198 struct maps *maps;
125 u64 mem_start, mem_end;199 u64 mem_start, mem_end;
126 bool header_printed;200 struct test__vmlinux_matches_kallsyms_cb_args args;
127 201
128 /*202 /*
129 * Step 1:203 * Step 1:
@@ -131,7 +205,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 1 unmodified line
131 * Init the machines that will hold kernel, modules obtained from205 * Init the machines that will hold kernel, modules obtained from
132 * both vmlinux + .ko files and from /proc/kallsyms split by modules.206 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
133 */207 */
134 machine__init(&kallsyms, "", HOST_KERNEL_ID);208 machine__init(&args.kallsyms, "", HOST_KERNEL_ID);
135 machine__init(&vmlinux, "", HOST_KERNEL_ID);209 machine__init(&vmlinux, "", HOST_KERNEL_ID);
136 210
137 maps = machine__kernel_maps(&vmlinux);211 maps = machine__kernel_maps(&vmlinux);
@@ -143,7 +217,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 5 unmodified lines
143 * load /proc/kallsyms. Also create the modules maps from /proc/modules217 * load /proc/kallsyms. Also create the modules maps from /proc/modules
144 * and find the .ko files that match them in /lib/modules/`uname -r`/.218 * and find the .ko files that match them in /lib/modules/`uname -r`/.
145 */219 */
146 if (machine__create_kernel_maps(&kallsyms) < 0) {220 if (machine__create_kernel_maps(&args.kallsyms) < 0) {
147 pr_debug("machine__create_kernel_maps failed");221 pr_debug("machine__create_kernel_maps failed");
148 err = TEST_SKIP;222 err = TEST_SKIP;
149 goto out;223 goto out;
@@ -160,7 +234,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 10 unmodified lines
160 * be compacted against the list of modules found in the "vmlinux"234 * be compacted against the list of modules found in the "vmlinux"
161 * code and with the one got from /proc/modules from the "kallsyms" code.235 * code and with the one got from /proc/modules from the "kallsyms" code.
162 */236 */
163 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms") <= 0) {237 if (machine__load_kallsyms(&args.kallsyms, "/proc/kallsyms") <= 0) {
164 pr_debug("machine__load_kallsyms failed");238 pr_debug("machine__load_kallsyms failed");
165 err = TEST_SKIP;239 err = TEST_SKIP;
166 goto out;240 goto out;
@@ -174,7 +248,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 7 unmodified lines
174 * to see if the running kernel was relocated by checking if it has the248 * to see if the running kernel was relocated by checking if it has the
175 * same value in the vmlinux file we load.249 * same value in the vmlinux file we load.
176 */250 */
177 kallsyms_map = machine__kernel_map(&kallsyms);251 kallsyms_map = machine__kernel_map(&args.kallsyms);
178 252
179 /*253 /*
180 * Step 5:254 * Step 5:
@@ -186,7 +260,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 5 unmodified lines
186 goto out;260 goto out;
187 }261 }
188 262
189 vmlinux_map = machine__kernel_map(&vmlinux);263 args.vmlinux_map = machine__kernel_map(&vmlinux);
190 264
191 /*265 /*
192 * Step 6:266 * Step 6:
@@ -213,7 +287,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 20 unmodified lines
213 * in the kallsyms dso. For the ones that are in both, check its names and287 * in the kallsyms dso. For the ones that are in both, check its names and
214 * end addresses too.288 * end addresses too.
215 */289 */
216 map__for_each_symbol(vmlinux_map, sym, nd) {290 map__for_each_symbol(args.vmlinux_map, sym, nd) {
217 struct symbol *pair, *first_pair;291 struct symbol *pair, *first_pair;
218 292
219 sym = rb_entry(nd, struct symbol, rb_node);293 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
221 if (sym->start == sym->end)295 if (sym->start == sym->end)
222 continue;296 continue;
223 297
224 mem_start = map__unmap_ip(vmlinux_map, sym->start);298 mem_start = map__unmap_ip(args.vmlinux_map, sym->start);
225 mem_end = map__unmap_ip(vmlinux_map, sym->end);299 mem_end = map__unmap_ip(args.vmlinux_map, sym->end);
226 300
227 first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL);301 first_pair = machine__find_kernel_symbol(&args.kallsyms, mem_start, NULL);
228 pair = first_pair;302 pair = first_pair;
229 303
230 if (pair && UM(pair->start) == mem_start) {304 if (pair && UM(pair->start) == mem_start) {
@@ -253,7 +327,8 @@ next_pair: · 22 unmodified lines
253 */327 */
254 continue;328 continue;
255 } else {329 } 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);
257 if (pair) {332 if (pair) {
258 if (UM(pair->start) == mem_start)333 if (UM(pair->start) == mem_start)
259 goto next_pair;334 goto next_pair;
@@ -267,7 +342,7 @@ next_pair: · 7 unmodified lines
267 342
268 continue;343 continue;
269 }344 }
270 } else if (mem_start == map__end(kallsyms.vmlinux_map)) {345 } else if (mem_start == map__end(args.kallsyms.vmlinux_map)) {
271 /*346 /*
272 * Ignore aliases to _etext, i.e. to the end of the kernel text area,347 * Ignore aliases to _etext, i.e. to the end of the kernel text area,
273 * such as __indirect_thunk_end.348 * such as __indirect_thunk_end.
@@ -289,78 +364,18 @@ next_pair: · 15 unmodified lines
289 if (verbose <= 0)364 if (verbose <= 0)
290 goto out;365 goto out;
291 366
292 header_printed = false;367 args.header_printed = false;
293 368 maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb1, &args);
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));
324 369
325 pair = maps__find(kallsyms.kmaps, mem_start);370 args.header_printed = false;
326 if (pair == NULL || map__priv(pair))371 maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb2, &args);
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);
350 372
351 maps__for_each_entry(maps, rb_node) {373 args.header_printed = false;
352 struct map *map = rb_node->map;374 maps = machine__kernel_maps(&args.kallsyms);
375 maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb3, &args);
353 376
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 }
362out:377out:
363 machine__exit(&kallsyms);378 machine__exit(&args.kallsyms);
364 machine__exit(&vmlinux);379 machine__exit(&vmlinux);
365 return err;380 return err;
366}381}
tools/perf/tests/workloads/thloop.c+1−3
@@ -7,7 +7,6 @@ · 6 unmodified lines
7#include "../tests.h"7#include "../tests.h"
8 8
9static volatile sig_atomic_t done;9static volatile sig_atomic_t done;
10static volatile unsigned count;
11 10
12/* We want to check this symbol in perf report */11/* We want to check this symbol in perf report */
13noinline void test_loop(void);12noinline void test_loop(void);
@@ -19,8 +18,7 @@ static void sighandler(int sig __maybe_unused) · 5 unmodified lines
19 18
20noinline void test_loop(void)19noinline void test_loop(void)
21{20{
22 while (!done)21 while (!done);
23 __atomic_fetch_add(&count, 1, __ATOMIC_RELAXED);
24}22}
25 23
26static void *thfunc(void *arg)24static 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
57 archlist="$1"57 archlist="$1"
58 default="$2"58 default="$2"
59 59
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'
61 printf '{\n'61 printf '{\n'
62 for arch in $archlist; do62 for arch in $archlist; do
63 printf '\tif (!strcmp(arch, "%s"))\n' $(arch_string "$arch")63 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")
65 done65 done
66 printf '\treturn errno_to_name__%s(err);\n' $(arch_string "$default")66 printf '\treturn errno_to_name__%s;\n' $(arch_string "$default")
67 printf '}\n'67 printf '}\n'
68}68}
69 69
@@ -76,7 +76,9 @@ EoHEADER · 6 unmodified lines
76 76
77# Create list of architectures that have a specific errno.h.77# Create list of architectures that have a specific errno.h.
78archlist=""78archlist=""
79for arch in $(find $toolsdir/arch -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | sort -r); do79for f in $toolsdir/arch/*/include/uapi/asm/errno.h; do
80 d=${f%/include/uapi/asm/errno.h}
81 arch="${d##*/}"
80 test -f $toolsdir/arch/$arch/include/uapi/asm/errno.h && archlist="$archlist $arch"82 test -f $toolsdir/arch/$arch/include/uapi/asm/errno.h && archlist="$archlist $arch"
81done83done
82 84
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
251void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,251void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
252 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg));252 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg));
253 253
254const char *arch_syscalls__strerrno(const char *arch, int err);
255
256#endif /* _PERF_TRACE_BEAUTY_H */254#endif /* _PERF_TRACE_BEAUTY_H */
tools/perf/trace/beauty/prctl_option.sh+2−2
@@ -4,9 +4,9 @@ · 3 unmodified lines
4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/4[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
5 5
6printf "static const char *prctl_options[] = {\n"6printf "static const char *prctl_options[] = {\n"
7regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$'7regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*/.*)?$'
8grep -E $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \8grep -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" | \
10 sort -n | xargs printf "\t[%s] = \"%s\",\n"10 sort -n | xargs printf "\t[%s] = \"%s\",\n"
11printf "};\n"11printf "};\n"
12 12
tools/perf/trace/beauty/socket.sh+2−2
@@ -18,10 +18,10 @@ grep -E $ipproto_regex ${uapi_header_dir}/in.h | \ · 17 unmodified lines
18printf "};\n\n"18printf "};\n\n"
19 19
20printf "static const char *socket_level[] = {\n"20printf "static const char *socket_level[] = {\n"
21socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+\/.*)?'21socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+/.*)?'
22 22
23grep -E $socket_level_regex ${beauty_header_dir}/socket.h | \23grep -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" | \
25 sort -n | xargs printf "\t[%s] = \"%s\",\n"25 sort -n | xargs printf "\t[%s] = \"%s\",\n"
26printf "};\n\n"26printf "};\n\n"
27 27
tools/perf/ui/browsers/annotate.c+48−56
@@ -27,7 +27,6 @@ struct annotate_browser { · 26 unmodified lines
27 struct rb_node *curr_hot;27 struct rb_node *curr_hot;
28 struct annotation_line *selection;28 struct annotation_line *selection;
29 struct arch *arch;29 struct arch *arch;
30 struct annotation_options *opts;
31 bool searching_backwards;30 bool searching_backwards;
32 char search_bf[128];31 char search_bf[128];
33};32};
@@ -38,11 +37,10 @@ static inline struct annotation *browser__annotation(struct ui_browser *browser) · 4 unmodified lines
38 return symbol__annotation(ms->sym);37 return symbol__annotation(ms->sym);
39}38}
40 39
41static bool disasm_line__filter(struct ui_browser *browser, void *entry)40static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry)
42{41{
43 struct annotation *notes = browser__annotation(browser);
44 struct annotation_line *al = list_entry(entry, struct annotation_line, node);42 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
45 return annotation_line__filter(al, notes);43 return annotation_line__filter(al);
46}44}
47 45
48static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)46static 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
97 struct annotation_write_ops ops = {95 struct annotation_write_ops ops = {
98 .first_line = row == 0,96 .first_line = row == 0,
99 .current_entry = is_current_entry,97 .current_entry = is_current_entry,
100 .change_color = (!notes->options->hide_src_code &&98 .change_color = (!annotate_opts.hide_src_code &&
101 (!is_current_entry ||99 (!is_current_entry ||
102 (browser->use_navkeypressed &&100 (browser->use_navkeypressed &&
103 !browser->navkeypressed))),101 !browser->navkeypressed))),
@@ -114,7 +112,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int · 10 unmodified lines
114 if (!browser->navkeypressed)112 if (!browser->navkeypressed)
115 ops.width += 1;113 ops.width += 1;
116 114
117 annotation_line__write(al, notes, &ops, ab->opts);115 annotation_line__write(al, notes, &ops);
118 116
119 if (ops.current_entry)117 if (ops.current_entry)
120 ab->selection = al;118 ab->selection = al;
@@ -128,7 +126,7 @@ static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor) · 7 unmodified lines
128 126
129 while (pos && pos->al.offset == -1) {127 while (pos && pos->al.offset == -1) {
130 pos = list_prev_entry(pos, al.node);128 pos = list_prev_entry(pos, al.node);
131 if (!ab->opts->hide_src_code)129 if (!annotate_opts.hide_src_code)
132 diff++;130 diff++;
133 }131 }
134 132
@@ -188,14 +186,14 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) · 53 unmodified lines
188 * name right after the '<' token and probably treating this like a186 * name right after the '<' token and probably treating this like a
189 * 'call' instruction.187 * 'call' instruction.
190 */188 */
191 target = notes->offsets[cursor->ops.target.offset];189 target = notes->src->offsets[cursor->ops.target.offset];
192 if (target == NULL) {190 if (target == NULL) {
193 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",191 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
194 cursor->ops.target.offset);192 cursor->ops.target.offset);
195 return;193 return;
196 }194 }
197 195
198 if (notes->options->hide_src_code) {196 if (annotate_opts.hide_src_code) {
199 from = cursor->al.idx_asm;197 from = cursor->al.idx_asm;
200 to = target->idx_asm;198 to = target->idx_asm;
201 } else {199 } else {
@@ -224,7 +222,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) · 22 unmodified lines
224 int ret = ui_browser__list_head_refresh(browser);222 int ret = ui_browser__list_head_refresh(browser);
225 int pcnt_width = annotation__pcnt_width(notes);223 int pcnt_width = annotation__pcnt_width(notes);
226 224
227 if (notes->options->jump_arrows)225 if (annotate_opts.jump_arrows)
228 annotate_browser__draw_current_jump(browser);226 annotate_browser__draw_current_jump(browser);
229 227
230 ui_browser__set_color(browser, HE_COLORSET_NORMAL);228 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
258 parent = *p;256 parent = *p;
259 l = rb_entry(parent, struct annotation_line, rb_node);257 l = rb_entry(parent, struct annotation_line, rb_node);
260 258
261 if (disasm__cmp(al, l, browser->opts->percent_type) < 0)259 if (disasm__cmp(al, l, annotate_opts.percent_type) < 0)
262 p = &(*p)->rb_left;260 p = &(*p)->rb_left;
263 else261 else
264 p = &(*p)->rb_right;262 p = &(*p)->rb_right;
@@ -270,7 +268,6 @@ static void disasm_rb_tree__insert(struct annotate_browser *browser, · 5 unmodified lines
270static void annotate_browser__set_top(struct annotate_browser *browser,268static void annotate_browser__set_top(struct annotate_browser *browser,
271 struct annotation_line *pos, u32 idx)269 struct annotation_line *pos, u32 idx)
272{270{
273 struct annotation *notes = browser__annotation(&browser->b);
274 unsigned back;271 unsigned back;
275 272
276 ui_browser__refresh_dimensions(&browser->b);273 ui_browser__refresh_dimensions(&browser->b);
@@ -280,7 +277,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser, · 3 unmodified lines
280 while (browser->b.top_idx != 0 && back != 0) {277 while (browser->b.top_idx != 0 && back != 0) {
281 pos = list_entry(pos->node.prev, struct annotation_line, node);278 pos = list_entry(pos->node.prev, struct annotation_line, node);
282 279
283 if (annotation_line__filter(pos, notes))280 if (annotation_line__filter(pos))
284 continue;281 continue;
285 282
286 --browser->b.top_idx;283 --browser->b.top_idx;
@@ -294,11 +291,10 @@ static void annotate_browser__set_top(struct annotate_browser *browser, · 7 unmodified lines
294static void annotate_browser__set_rb_top(struct annotate_browser *browser,291static void annotate_browser__set_rb_top(struct annotate_browser *browser,
295 struct rb_node *nd)292 struct rb_node *nd)
296{293{
297 struct annotation *notes = browser__annotation(&browser->b);
298 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);294 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
299 u32 idx = pos->idx;295 u32 idx = pos->idx;
300 296
301 if (notes->options->hide_src_code)297 if (annotate_opts.hide_src_code)
302 idx = pos->idx_asm;298 idx = pos->idx_asm;
303 annotate_browser__set_top(browser, pos, idx);299 annotate_browser__set_top(browser, pos, idx);
304 browser->curr_hot = nd;300 browser->curr_hot = nd;
@@ -331,13 +327,13 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, · 26 unmodified lines
331 double percent;327 double percent;
332 328
333 percent = annotation_data__percent(&pos->al.data[i],329 percent = annotation_data__percent(&pos->al.data[i],
334 browser->opts->percent_type);330 annotate_opts.percent_type);
335 331
336 if (max_percent < percent)332 if (max_percent < percent)
337 max_percent = percent;333 max_percent = percent;
338 }334 }
339 335
340 if (max_percent < 0.01 && pos->al.ipc == 0) {336 if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) {
341 RB_CLEAR_NODE(&pos->al.rb_node);337 RB_CLEAR_NODE(&pos->al.rb_node);
342 continue;338 continue;
343 }339 }
@@ -380,12 +376,12 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) · 36 unmodified lines
380 browser->b.seek(&browser->b, offset, SEEK_CUR);376 browser->b.seek(&browser->b, offset, SEEK_CUR);
381 al = list_entry(browser->b.top, struct annotation_line, node);377 al = list_entry(browser->b.top, struct annotation_line, node);
382 378
383 if (notes->options->hide_src_code) {379 if (annotate_opts.hide_src_code) {
384 if (al->idx_asm < offset)380 if (al->idx_asm < offset)
385 offset = al->idx;381 offset = al->idx;
386 382
387 browser->b.nr_entries = notes->nr_entries;383 browser->b.nr_entries = notes->src->nr_entries;
388 notes->options->hide_src_code = false;384 annotate_opts.hide_src_code = false;
389 browser->b.seek(&browser->b, -offset, SEEK_CUR);385 browser->b.seek(&browser->b, -offset, SEEK_CUR);
390 browser->b.top_idx = al->idx - offset;386 browser->b.top_idx = al->idx - offset;
391 browser->b.index = al->idx;387 browser->b.index = al->idx;
@@ -402,8 +398,8 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) · 10 unmodified lines
402 if (al->idx_asm < offset)398 if (al->idx_asm < offset)
403 offset = al->idx_asm;399 offset = al->idx_asm;
404 400
405 browser->b.nr_entries = notes->nr_asm_entries;401 browser->b.nr_entries = notes->src->nr_asm_entries;
406 notes->options->hide_src_code = true;402 annotate_opts.hide_src_code = true;
407 browser->b.seek(&browser->b, -offset, SEEK_CUR);403 browser->b.seek(&browser->b, -offset, SEEK_CUR);
408 browser->b.top_idx = al->idx_asm - offset;404 browser->b.top_idx = al->idx_asm - offset;
409 browser->b.index = al->idx_asm;405 browser->b.index = al->idx_asm;
@@ -435,7 +431,7 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) · 25 unmodified lines
435{431{
436 struct annotation *notes = browser__annotation(browser);432 struct annotation *notes = browser__annotation(browser);
437 ui_browser__reset_index(browser);433 ui_browser__reset_index(browser);
438 browser->nr_entries = notes->nr_asm_entries;434 browser->nr_entries = notes->src->nr_asm_entries;
439}435}
440 436
441static int sym_title(struct symbol *sym, struct map *map, char *title,437static 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
483 target_ms.map = ms->map;479 target_ms.map = ms->map;
484 target_ms.sym = dl->ops.target.sym;480 target_ms.sym = dl->ops.target.sym;
485 annotation__unlock(notes);481 annotation__unlock(notes);
486 symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);482 symbol__tui_annotate(&target_ms, evsel, hbt);
487 sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);483 sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type);
488 ui_browser__show_title(&browser->b, title);484 ui_browser__show_title(&browser->b, title);
489 return true;485 return true;
490}486}
@@ -500,7 +496,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows · 9 unmodified lines
500 list_for_each_entry(pos, &notes->src->source, al.node) {496 list_for_each_entry(pos, &notes->src->source, al.node) {
501 if (pos->al.offset == offset)497 if (pos->al.offset == offset)
502 return pos;498 return pos;
503 if (!annotation_line__filter(&pos->al, notes))499 if (!annotation_line__filter(&pos->al))
504 ++*idx;500 ++*idx;
505 }501 }
506 502
@@ -544,7 +540,7 @@ struct annotation_line *annotate_browser__find_string(struct annotate_browser *b · 37 unmodified lines
544 540
545 *idx = browser->b.index;541 *idx = browser->b.index;
546 list_for_each_entry_continue(al, &notes->src->source, node) {542 list_for_each_entry_continue(al, &notes->src->source, node) {
547 if (annotation_line__filter(al, notes))543 if (annotation_line__filter(al))
548 continue;544 continue;
549 545
550 ++*idx;546 ++*idx;
@@ -581,7 +577,7 @@ struct annotation_line *annotate_browser__find_string_reverse(struct annotate_br · 30 unmodified lines
581 577
582 *idx = browser->b.index;578 *idx = browser->b.index;
583 list_for_each_entry_continue_reverse(al, &notes->src->source, node) {579 list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
584 if (annotation_line__filter(al, notes))580 if (annotation_line__filter(al))
585 continue;581 continue;
586 582
587 --*idx;583 --*idx;
@@ -659,7 +655,6 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, · 71 unmodified lines
659 655
660static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)656static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
661{657{
662 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
663 struct map_symbol *ms = browser->priv;658 struct map_symbol *ms = browser->priv;
664 struct symbol *sym = ms->sym;659 struct symbol *sym = ms->sym;
665 char symbol_dso[SYM_TITLE_MAX_SIZE];660 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
667 if (ui_browser__show(browser, title, help) < 0)662 if (ui_browser__show(browser, title, help) < 0)
668 return -1;663 return -1;
669 664
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);
671 666
672 ui_browser__gotorc_title(browser, 0, 0);667 ui_browser__gotorc_title(browser, 0, 0);
673 ui_browser__set_color(browser, HE_COLORSET_ROOT);668 ui_browser__set_color(browser, HE_COLORSET_ROOT);
@@ -809,7 +804,7 @@ static int annotate_browser__run(struct annotate_browser *browser, · 135 unmodified lines
809 annotate_browser__show(&browser->b, title, help);804 annotate_browser__show(&browser->b, title, help);
810 continue;805 continue;
811 case 'k':806 case 'k':
812 notes->options->show_linenr = !notes->options->show_linenr;807 annotate_opts.show_linenr = !annotate_opts.show_linenr;
813 continue;808 continue;
814 case 'l':809 case 'l':
815 annotate_browser__show_full_location (&browser->b);810 annotate_browser__show_full_location (&browser->b);
@@ -822,18 +817,18 @@ static int annotate_browser__run(struct annotate_browser *browser, · 6 unmodified lines
822 ui_helpline__puts(help);817 ui_helpline__puts(help);
823 continue;818 continue;
824 case 'o':819 case 'o':
825 notes->options->use_offset = !notes->options->use_offset;820 annotate_opts.use_offset = !annotate_opts.use_offset;
826 annotation__update_column_widths(notes);821 annotation__update_column_widths(notes);
827 continue;822 continue;
828 case 'O':823 case 'O':
829 if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)824 if (++annotate_opts.offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
830 notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;825 annotate_opts.offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
831 continue;826 continue;
832 case 'j':827 case 'j':
833 notes->options->jump_arrows = !notes->options->jump_arrows;828 annotate_opts.jump_arrows = !annotate_opts.jump_arrows;
834 continue;829 continue;
835 case 'J':830 case 'J':
836 notes->options->show_nr_jumps = !notes->options->show_nr_jumps;831 annotate_opts.show_nr_jumps = !annotate_opts.show_nr_jumps;
837 annotation__update_column_widths(notes);832 annotation__update_column_widths(notes);
838 continue;833 continue;
839 case '/':834 case '/':
@@ -860,7 +855,7 @@ show_help: · 20 unmodified lines
860 browser->b.height,855 browser->b.height,
861 browser->b.index,856 browser->b.index,
862 browser->b.top_idx,857 browser->b.top_idx,
863 notes->nr_asm_entries);858 notes->src->nr_asm_entries);
864 }859 }
865 continue;860 continue;
866 case K_ENTER:861 case K_ENTER:
@@ -884,7 +879,7 @@ show_sup_ins: · 17 unmodified lines
884 continue;879 continue;
885 }880 }
886 case 'P':881 case 'P':
887 map_symbol__annotation_dump(ms, evsel, browser->opts);882 map_symbol__annotation_dump(ms, evsel);
888 continue;883 continue;
889 case 't':884 case 't':
890 if (symbol_conf.show_total_period) {885 if (symbol_conf.show_total_period) {
@@ -897,15 +892,15 @@ show_sup_ins: · 6 unmodified lines
897 annotation__update_column_widths(notes);892 annotation__update_column_widths(notes);
898 continue;893 continue;
899 case 'c':894 case 'c':
900 if (notes->options->show_minmax_cycle)895 if (annotate_opts.show_minmax_cycle)
901 notes->options->show_minmax_cycle = false;896 annotate_opts.show_minmax_cycle = false;
902 else897 else
903 notes->options->show_minmax_cycle = true;898 annotate_opts.show_minmax_cycle = true;
904 annotation__update_column_widths(notes);899 annotation__update_column_widths(notes);
905 continue;900 continue;
906 case 'p':901 case 'p':
907 case 'b':902 case 'b':
908 switch_percent_type(browser->opts, key == 'b');903 switch_percent_type(&annotate_opts, key == 'b');
909 hists__scnprintf_title(hists, title, sizeof(title));904 hists__scnprintf_title(hists, title, sizeof(title));
910 annotate_browser__show(&browser->b, title, help);905 annotate_browser__show(&browser->b, title, help);
911 continue;906 continue;
@@ -932,26 +927,24 @@ out: · 20 unmodified lines
932}927}
933 928
934int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,929int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
935 struct hist_browser_timer *hbt,930 struct hist_browser_timer *hbt)
936 struct annotation_options *opts)
937{931{
938 return symbol__tui_annotate(ms, evsel, hbt, opts);932 return symbol__tui_annotate(ms, evsel, hbt);
939}933}
940 934
941int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,935int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
942 struct hist_browser_timer *hbt,936 struct hist_browser_timer *hbt)
943 struct annotation_options *opts)
944{937{
945 /* reset abort key so that it can get Ctrl-C as a key */938 /* reset abort key so that it can get Ctrl-C as a key */
946 SLang_reset_tty();939 SLang_reset_tty();
947 SLang_init_tty(0, 0, 0);940 SLang_init_tty(0, 0, 0);
941 SLtty_set_suspend_state(true);
948 942
949 return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);943 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
950}944}
951 945
952int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,946int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
953 struct hist_browser_timer *hbt,947 struct hist_browser_timer *hbt)
954 struct annotation_options *opts)
955{948{
956 struct symbol *sym = ms->sym;949 struct symbol *sym = ms->sym;
957 struct annotation *notes = symbol__annotation(sym);950 struct annotation *notes = symbol__annotation(sym);
@@ -965,7 +958,6 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 7 unmodified lines
965 .priv = ms,958 .priv = ms,
966 .use_navkeypressed = true,959 .use_navkeypressed = true,
967 },960 },
968 .opts = opts,
969 };961 };
970 struct dso *dso;962 struct dso *dso;
971 int ret = -1, err;963 int ret = -1, err;
@@ -979,7 +971,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 7 unmodified lines
979 return -1;971 return -1;
980 972
981 if (not_annotated) {973 if (not_annotated) {
982 err = symbol__annotate2(ms, evsel, opts, &browser.arch);974 err = symbol__annotate2(ms, evsel, &browser.arch);
983 if (err) {975 if (err) {
984 char msg[BUFSIZ];976 char msg[BUFSIZ];
985 dso->annotate_warned = true;977 dso->annotate_warned = true;
@@ -991,12 +983,12 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 5 unmodified lines
991 983
992 ui_helpline__push("Press ESC to exit");984 ui_helpline__push("Press ESC to exit");
993 985
994 browser.b.width = notes->max_line_len;986 browser.b.width = notes->src->max_line_len;
995 browser.b.nr_entries = notes->nr_entries;987 browser.b.nr_entries = notes->src->nr_entries;
996 browser.b.entries = &notes->src->source,988 browser.b.entries = &notes->src->source,
997 browser.b.width += 18; /* Percentage */989 browser.b.width += 18; /* Percentage */
998 990
999 if (notes->options->hide_src_code)991 if (annotate_opts.hide_src_code)
1000 ui_browser__init_asm_mode(&browser.b);992 ui_browser__init_asm_mode(&browser.b);
1001 993
1002 ret = annotate_browser__run(&browser, evsel, hbt);994 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
1006 998
1007out_free_offsets:999out_free_offsets:
1008 if(not_annotated)1000 if(not_annotated)
1009 zfree(&notes->offsets);1001 zfree(&notes->src->offsets);
1010 return ret;1002 return ret;
1011}1003}
tools/perf/ui/browsers/hists.c+14−22
@@ -2250,8 +2250,7 @@ struct hist_browser *hist_browser__new(struct hists *hists) · 2249 unmodified lines
2250static struct hist_browser *2250static struct hist_browser *
2251perf_evsel_browser__new(struct evsel *evsel,2251perf_evsel_browser__new(struct evsel *evsel,
2252 struct hist_browser_timer *hbt,2252 struct hist_browser_timer *hbt,
2253 struct perf_env *env,2253 struct perf_env *env)
2254 struct annotation_options *annotation_opts)
2255{2254{
2256 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));2255 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
2257 2256
@@ -2259,7 +2258,6 @@ perf_evsel_browser__new(struct evsel *evsel, · 1 unmodified line
2259 browser->hbt = hbt;2258 browser->hbt = hbt;
2260 browser->env = env;2259 browser->env = env;
2261 browser->title = hists_browser__scnprintf_title;2260 browser->title = hists_browser__scnprintf_title;
2262 browser->annotation_opts = annotation_opts;
2263 }2261 }
2264 return browser;2262 return browser;
2265}2263}
@@ -2432,8 +2430,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) · 166 unmodified lines
2432 struct hist_entry *he;2430 struct hist_entry *he;
2433 int err;2431 int err;
2434 2432
2435 if (!browser->annotation_opts->objdump_path &&2433 if (!annotate_opts.objdump_path &&
2436 perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))2434 perf_env__lookup_objdump(browser->env, &annotate_opts.objdump_path))
2437 return 0;2435 return 0;
2438 2436
2439 notes = symbol__annotation(act->ms.sym);2437 notes = symbol__annotation(act->ms.sym);
@@ -2445,8 +2443,7 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) · 5 unmodified lines
2445 else2443 else
2446 evsel = hists_to_evsel(browser->hists);2444 evsel = hists_to_evsel(browser->hists);
2447 2445
2448 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,2446 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
2449 browser->annotation_opts);
2450 he = hist_browser__selected_entry(browser);2447 he = hist_browser__selected_entry(browser);
2451 /*2448 /*
2452 * offer option to annotate the other branch source or target2449 * offer option to annotate the other branch source or target
@@ -2943,11 +2940,10 @@ next: · 490 unmodified lines
2943 2940
2944static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline,2941static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline,
2945 bool left_exits, struct hist_browser_timer *hbt, float min_pcnt,2942 bool left_exits, struct hist_browser_timer *hbt, float min_pcnt,
2946 struct perf_env *env, bool warn_lost_event,2943 struct perf_env *env, bool warn_lost_event)
2947 struct annotation_options *annotation_opts)
2948{2944{
2949 struct hists *hists = evsel__hists(evsel);2945 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);
2951 struct branch_info *bi = NULL;2947 struct branch_info *bi = NULL;
2952#define MAX_OPTIONS 162948#define MAX_OPTIONS 16
2953 char *options[MAX_OPTIONS];2949 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
3004 /* reset abort key so that it can get Ctrl-C as a key */3000 /* reset abort key so that it can get Ctrl-C as a key */
3005 SLang_reset_tty();3001 SLang_reset_tty();
3006 SLang_init_tty(0, 0, 0);3002 SLang_init_tty(0, 0, 0);
3003 SLtty_set_suspend_state(true);
3007 3004
3008 if (min_pcnt)3005 if (min_pcnt)
3009 browser->min_pcnt = min_pcnt;3006 browser->min_pcnt = min_pcnt;
@@ -3398,7 +3395,6 @@ out: · 388 unmodified lines
3398struct evsel_menu {3395struct evsel_menu {
3399 struct ui_browser b;3396 struct ui_browser b;
3400 struct evsel *selection;3397 struct evsel *selection;
3401 struct annotation_options *annotation_opts;
3402 bool lost_events, lost_events_warned;3398 bool lost_events, lost_events_warned;
3403 float min_pcnt;3399 float min_pcnt;
3404 struct perf_env *env;3400 struct perf_env *env;
@@ -3499,8 +3495,7 @@ browse_hists: · 94 unmodified lines
3499 hbt->timer(hbt->arg);3495 hbt->timer(hbt->arg);
3500 key = evsel__hists_browse(pos, nr_events, help, true, hbt,3496 key = evsel__hists_browse(pos, nr_events, help, true, hbt,
3501 menu->min_pcnt, menu->env,3497 menu->min_pcnt, menu->env,
3502 warn_lost_event,3498 warn_lost_event);
3503 menu->annotation_opts);
3504 ui_browser__show_title(&menu->b, title);3499 ui_browser__show_title(&menu->b, title);
3505 switch (key) {3500 switch (key) {
3506 case K_TAB:3501 case K_TAB:
@@ -3557,7 +3552,7 @@ static bool filter_group_entries(struct ui_browser *browser __maybe_unused, · 50 unmodified lines
3557 3552
3558static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help,3553static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help,
3559 struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env,3554 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)
3561{3556{
3562 struct evsel *pos;3557 struct evsel *pos;
3563 struct evsel_menu menu = {3558 struct evsel_menu menu = {
@@ -3572,7 +3567,6 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con · 8 unmodified lines
3572 },3567 },
3573 .min_pcnt = min_pcnt,3568 .min_pcnt = min_pcnt,
3574 .env = env,3569 .env = env,
3575 .annotation_opts = annotation_opts,
3576 };3570 };
3577 3571
3578 ui_helpline__push("Press ESC to exit");3572 ui_helpline__push("Press ESC to exit");
@@ -3607,8 +3601,7 @@ static bool evlist__single_entry(struct evlist *evlist) · 28 unmodified lines
3607}3601}
3608 3602
3609int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,3603int 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,3604 float min_pcnt, struct perf_env *env, bool warn_lost_event)
3611 struct annotation_options *annotation_opts)
3612{3605{
3613 int nr_entries = evlist->core.nr_entries;3606 int nr_entries = evlist->core.nr_entries;
3614 3607
@@ -3617,7 +3610,7 @@ single_entry: { · 2 unmodified lines
3617 struct evsel *first = evlist__first(evlist);3610 struct evsel *first = evlist__first(evlist);
3618 3611
3619 return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt,3612 return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt,
3620 env, warn_lost_event, annotation_opts);3613 env, warn_lost_event);
3621 }3614 }
3622 }3615 }
3623 3616
@@ -3635,7 +3628,7 @@ single_entry: { · 11 unmodified lines
3635 }3628 }
3636 3629
3637 return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env,3630 return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env,
3638 warn_lost_event, annotation_opts);3631 warn_lost_event);
3639}3632}
3640 3633
3641static int block_hists_browser__title(struct hist_browser *browser, char *bf,3634static 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
3654}3647}
3655 3648
3656int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,3649int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
3657 float min_percent, struct perf_env *env,3650 float min_percent, struct perf_env *env)
3658 struct annotation_options *annotation_opts)
3659{3651{
3660 struct hists *hists = &bh->block_hists;3652 struct hists *hists = &bh->block_hists;
3661 struct hist_browser *browser;3653 struct hist_browser *browser;
@@ -3672,11 +3664,11 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, · 10 unmodified lines
3672 browser->title = block_hists_browser__title;3664 browser->title = block_hists_browser__title;
3673 browser->min_pcnt = min_percent;3665 browser->min_pcnt = min_percent;
3674 browser->env = env;3666 browser->env = env;
3675 browser->annotation_opts = annotation_opts;
3676 3667
3677 /* reset abort key so that it can get Ctrl-C as a key */3668 /* reset abort key so that it can get Ctrl-C as a key */
3678 SLang_reset_tty();3669 SLang_reset_tty();
3679 SLang_init_tty(0, 0, 0);3670 SLang_init_tty(0, 0, 0);
3671 SLtty_set_suspend_state(true);
3680 3672
3681 memset(&action, 0, sizeof(action));3673 memset(&action, 0, sizeof(action));
3682 3674
tools/perf/ui/browsers/hists.h+0−2
@@ -4,7 +4,6 @@ · 3 unmodified lines
4 4
5#include "ui/browser.h"5#include "ui/browser.h"
6 6
7struct annotation_options;
8struct evsel;7struct evsel;
9 8
10struct hist_browser {9struct hist_browser {
@@ -15,7 +14,6 @@ struct hist_browser { · 4 unmodified lines
15 struct hist_browser_timer *hbt;14 struct hist_browser_timer *hbt;
16 struct pstack *pstack;15 struct pstack *pstack;
17 struct perf_env *env;16 struct perf_env *env;
18 struct annotation_options *annotation_opts;
19 struct evsel *block_evsel;17 struct evsel *block_evsel;
20 int print_seq;18 int print_seq;
21 bool show_dso;19 bool show_dso;
tools/perf/ui/browsers/scripts.c+1−0
@@ -166,6 +166,7 @@ void run_script(char *cmd) · 165 unmodified lines
166 printf("\033[c\033[H\033[J");166 printf("\033[c\033[H\033[J");
167 fflush(stdout);167 fflush(stdout);
168 SLang_init_tty(0, 0, 0);168 SLang_init_tty(0, 0, 0);
169 SLtty_set_suspend_state(true);
169 SLsmg_refresh();170 SLsmg_refresh();
170}171}
171 172
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
162}162}
163 163
164static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,164static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
165 struct annotation_options *options,
166 struct hist_browser_timer *hbt)165 struct hist_browser_timer *hbt)
167{166{
168 struct dso *dso = map__dso(ms->map);167 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
176 if (dso->annotate_warned)175 if (dso->annotate_warned)
177 return -1;176 return -1;
178 177
179 err = symbol__annotate(ms, evsel, options, NULL);178 err = symbol__annotate(ms, evsel, NULL);
180 if (err) {179 if (err) {
181 char msg[BUFSIZ];180 char msg[BUFSIZ];
182 dso->annotate_warned = true;181 dso->annotate_warned = true;
@@ -244,10 +243,9 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, · 61 unmodified lines
244 243
245int hist_entry__gtk_annotate(struct hist_entry *he,244int hist_entry__gtk_annotate(struct hist_entry *he,
246 struct evsel *evsel,245 struct evsel *evsel,
247 struct annotation_options *options,
248 struct hist_browser_timer *hbt)246 struct hist_browser_timer *hbt)
249{247{
250 return symbol__gtk_annotate(&he->ms, evsel, options, hbt);248 return symbol__gtk_annotate(&he->ms, evsel, hbt);
251}249}
252 250
253void perf_gtk__show_annotations(void)251void perf_gtk__show_annotations(void)
tools/perf/ui/gtk/gtk.h+0−2
@@ -56,13 +56,11 @@ struct evsel; · 55 unmodified lines
56struct evlist;56struct evlist;
57struct hist_entry;57struct hist_entry;
58struct hist_browser_timer;58struct hist_browser_timer;
59struct annotation_options;
60 59
61int evlist__gtk_browse_hists(struct evlist *evlist, const char *help,60int evlist__gtk_browse_hists(struct evlist *evlist, const char *help,
62 struct hist_browser_timer *hbt, float min_pcnt);61 struct hist_browser_timer *hbt, float min_pcnt);
63int hist_entry__gtk_annotate(struct hist_entry *he,62int hist_entry__gtk_annotate(struct hist_entry *he,
64 struct evsel *evsel,63 struct evsel *evsel,
65 struct annotation_options *options,
66 struct hist_browser_timer *hbt);64 struct hist_browser_timer *hbt);
67void perf_gtk__show_annotations(void);65void perf_gtk__show_annotations(void);
68 66
tools/perf/ui/tui/setup.c+22−0
@@ -2,12 +2,14 @@ · 1 unmodified line
2#include <signal.h>2#include <signal.h>
3#include <stdbool.h>3#include <stdbool.h>
4#include <stdlib.h>4#include <stdlib.h>
5#include <termios.h>
5#include <unistd.h>6#include <unistd.h>
6#include <linux/kernel.h>7#include <linux/kernel.h>
7#ifdef HAVE_BACKTRACE_SUPPORT8#ifdef HAVE_BACKTRACE_SUPPORT
8#include <execinfo.h>9#include <execinfo.h>
9#endif10#endif
10 11
12#include "../../util/color.h"
11#include "../../util/debug.h"13#include "../../util/debug.h"
12#include "../browser.h"14#include "../browser.h"
13#include "../helpline.h"15#include "../helpline.h"
@@ -121,6 +123,23 @@ static void ui__signal(int sig) · 107 unmodified lines
121 exit(0);123 exit(0);
122}124}
123 125
126static 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
124int ui__init(void)143int ui__init(void)
125{144{
126 int err;145 int err;
@@ -135,6 +154,7 @@ int ui__init(void) · 8 unmodified lines
135 err = SLang_init_tty(-1, 0, 0);154 err = SLang_init_tty(-1, 0, 0);
136 if (err < 0)155 if (err < 0)
137 goto out;156 goto out;
157 SLtty_set_suspend_state(true);
138 158
139 err = SLkp_init();159 err = SLkp_init();
140 if (err < 0) {160 if (err < 0) {
@@ -149,6 +169,8 @@ int ui__init(void) · 8 unmodified lines
149 signal(SIGINT, ui__signal);169 signal(SIGINT, ui__signal);
150 signal(SIGQUIT, ui__signal);170 signal(SIGQUIT, ui__signal);
151 signal(SIGTERM, ui__signal);171 signal(SIGTERM, ui__signal);
172 signal(SIGTSTP, ui__sigcont);
173 signal(SIGCONT, ui__sigcont);
152 174
153 perf_error__register(&perf_tui_eops);175 perf_error__register(&perf_tui_eops);
154 176
tools/perf/util/Build+2−0
@@ -195,6 +195,8 @@ endif · 194 unmodified lines
195perf-$(CONFIG_DWARF) += probe-finder.o195perf-$(CONFIG_DWARF) += probe-finder.o
196perf-$(CONFIG_DWARF) += dwarf-aux.o196perf-$(CONFIG_DWARF) += dwarf-aux.o
197perf-$(CONFIG_DWARF) += dwarf-regs.o197perf-$(CONFIG_DWARF) += dwarf-regs.o
198perf-$(CONFIG_DWARF) += debuginfo.o
199perf-$(CONFIG_DWARF) += annotate-data.o
198 200
199perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o201perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
200perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o202perf-$(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 */
30static 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
42static 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 */
55static 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
105static 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
112static 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
125static 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
169static 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 */
195static 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 */
235static 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
266out:
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 */
282struct 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
308out:
309 debuginfo__delete(di);
310 return result;
311}
312
313static 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
337err:
338 while (--i >= 0)
339 free(adt->histograms[i]);
340 free(adt->histograms);
341 return -ENOMEM;
342}
343
344static 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
351void 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 */
379int 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
10struct evsel;
11struct 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 */
24struct 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 */
38struct 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 */
49struct 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 */
64struct annotated_data_type {
65 struct rb_node node;
66 struct annotated_member self;
67 int nr_histograms;
68 struct type_hist **histograms;
69};
70
71extern 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 */
88struct 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};
102extern struct annotated_data_stat ann_data_stat;
103
104#ifdef HAVE_DWARF_SUPPORT
105
106/* Returns data type at the location (ip, reg, offset) */
107struct 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 */
111int 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 */
116void annotated_data_type__tree_delete(struct rb_root *root);
117
118#else /* HAVE_DWARF_SUPPORT */
119
120static inline struct annotated_data_type *
121find_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
127static inline int
128annotated_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
137static 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
25#include "units.h"25#include "units.h"
26#include "debug.h"26#include "debug.h"
27#include "annotate.h"27#include "annotate.h"
28#include "annotate-data.h"
28#include "evsel.h"29#include "evsel.h"
29#include "evlist.h"30#include "evlist.h"
30#include "bpf-event.h"31#include "bpf-event.h"
31#include "bpf-utils.h"32#include "bpf-utils.h"
32#include "block-range.h"33#include "block-range.h"
33#include "string2.h"34#include "string2.h"
35#include "dwarf-regs.h"
34#include "util/event.h"36#include "util/event.h"
35#include "util/sharded_mutex.h"37#include "util/sharded_mutex.h"
36#include "arch/common.h"38#include "arch/common.h"
@@ -57,6 +59,9 @@ · 20 unmodified lines
57 59
58#include <linux/ctype.h>60#include <linux/ctype.h>
59 61
62/* global annotation options */
63struct annotation_options annotate_opts;
64
60static regex_t file_lineno;65static regex_t file_lineno;
61 66
62static struct ins_ops *ins__find(struct arch *arch, const char *name);67static struct ins_ops *ins__find(struct arch *arch, const char *name);
@@ -85,6 +90,8 @@ struct arch { · 22 unmodified lines
85 struct {90 struct {
86 char comment_char;91 char comment_char;
87 char skip_functions_char;92 char skip_functions_char;
93 char register_char;
94 char memory_ref_char;
88 } objdump;95 } objdump;
89};96};
90 97
@@ -96,6 +103,10 @@ static struct ins_ops nop_ops; · 5 unmodified lines
96static struct ins_ops lock_ops;103static struct ins_ops lock_ops;
97static struct ins_ops ret_ops;104static struct ins_ops ret_ops;
98 105
106/* Data type collection debug statistics */
107struct annotated_data_stat ann_data_stat;
108LIST_HEAD(ann_insn_stat);
109
99static int arch__grow_instructions(struct arch *arch)110static int arch__grow_instructions(struct arch *arch)
100{111{
101 struct ins *new_instructions;112 struct ins *new_instructions;
@@ -188,6 +199,8 @@ static struct arch architectures[] = { · 86 unmodified lines
188 .insn_suffix = "bwlq",199 .insn_suffix = "bwlq",
189 .objdump = {200 .objdump = {
190 .comment_char = '#',201 .comment_char = '#',
202 .register_char = '%',
203 .memory_ref_char = '(',
191 },204 },
192 },205 },
193 {206 {
@@ -340,10 +353,10 @@ bool ins__is_call(const struct ins *ins) · 146 unmodified lines
340 */353 */
341static inline const char *validate_comma(const char *c, struct ins_operands *ops)354static inline const char *validate_comma(const char *c, struct ins_operands *ops)
342{355{
343 if (ops->raw_comment && c > ops->raw_comment)356 if (ops->jump.raw_comment && c > ops->jump.raw_comment)
344 return NULL;357 return NULL;
345 358
346 if (ops->raw_func_start && c > ops->raw_func_start)359 if (ops->jump.raw_func_start && c > ops->jump.raw_func_start)
347 return NULL;360 return NULL;
348 361
349 return c;362 return c;
@@ -359,8 +372,8 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s · 9 unmodified lines
359 const char *c = strchr(ops->raw, ',');372 const char *c = strchr(ops->raw, ',');
360 u64 start, end;373 u64 start, end;
361 374
362 ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);375 ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char);
363 ops->raw_func_start = strchr(ops->raw, '<');376 ops->jump.raw_func_start = strchr(ops->raw, '<');
364 377
365 c = validate_comma(c, ops);378 c = validate_comma(c, ops);
366 379
@@ -462,7 +475,16 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, · 95 unmodified lines
462 ops->target.offset);475 ops->target.offset);
463}476}
464 477
478static 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
465static struct ins_ops jump_ops = {486static struct ins_ops jump_ops = {
487 .free = jump__delete,
466 .parse = jump__parse,488 .parse = jump__parse,
467 .scnprintf = jump__scnprintf,489 .scnprintf = jump__scnprintf,
468};490};
@@ -557,6 +579,34 @@ static struct ins_ops lock_ops = { · 88 unmodified lines
557 .scnprintf = lock__scnprintf,579 .scnprintf = lock__scnprintf,
558};580};
559 581
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 */
589static 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
560static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)610static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
561{611{
562 char *s = strchr(ops->raw, ','), *target, *comment, prev;612 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
584 if (ops->source.raw == NULL)634 if (ops->source.raw == NULL)
585 return -1;635 return -1;
586 636
637 ops->source.multi_regs = check_multi_regs(arch, ops->source.raw);
638
587 target = skip_spaces(++s);639 target = skip_spaces(++s);
588 comment = strchr(s, arch->objdump.comment_char);640 comment = strchr(s, arch->objdump.comment_char);
589 641
@@ -604,6 +656,8 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_sy · 14 unmodified lines
604 if (ops->target.raw == NULL)656 if (ops->target.raw == NULL)
605 goto out_free_source;657 goto out_free_source;
606 658
659 ops->target.multi_regs = check_multi_regs(arch, ops->target.raw);
660
607 if (comment == NULL)661 if (comment == NULL)
608 return 0;662 return 0;
609 663
@@ -795,6 +849,11 @@ static struct arch *arch__find(const char *name) · 185 unmodified lines
795 return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);849 return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
796}850}
797 851
852bool arch__is(struct arch *arch, const char *name)
853{
854 return !strcmp(arch->name, name);
855}
856
798static struct annotated_source *annotated_source__new(void)857static struct annotated_source *annotated_source__new(void)
799{858{
800 struct annotated_source *src = zalloc(sizeof(*src));859 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
810 if (src == NULL)869 if (src == NULL)
811 return;870 return;
812 zfree(&src->histograms);871 zfree(&src->histograms);
813 zfree(&src->cycles_hist);
814 free(src);872 free(src);
815}873}
816 874
@@ -845,18 +903,6 @@ static int annotated_source__alloc_histograms(struct annotated_source *src, · 28 unmodified lines
845 return src->histograms ? 0 : -1;903 return src->histograms ? 0 : -1;
846}904}
847 905
848/* The cycles histogram is lazily allocated. */
849static 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
860void symbol__annotate_zero_histograms(struct symbol *sym)906void symbol__annotate_zero_histograms(struct symbol *sym)
861{907{
862 struct annotation *notes = symbol__annotation(sym);908 struct annotation *notes = symbol__annotation(sym);
@@ -865,9 +911,10 @@ void symbol__annotate_zero_histograms(struct symbol *sym) · 2 unmodified lines
865 if (notes->src != NULL) {911 if (notes->src != NULL) {
866 memset(notes->src->histograms, 0,912 memset(notes->src->histograms, 0,
867 notes->src->nr_histograms * notes->src->sizeof_sym_hist);913 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
868 if (notes->src->cycles_hist)914 }
869 memset(notes->src->cycles_hist, 0,915 if (notes->branch && notes->branch->cycles_hist) {
870 symbol__size(sym) * sizeof(struct cyc_hist));916 memset(notes->branch->cycles_hist, 0,
917 symbol__size(sym) * sizeof(struct cyc_hist));
871 }918 }
872 annotation__unlock(notes);919 annotation__unlock(notes);
873}920}
@@ -958,23 +1005,33 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms, · 84 unmodified lines
958 return 0;1005 return 0;
959}1006}
960 1007
1008struct 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
961static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)1019static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
962{1020{
963 struct annotation *notes = symbol__annotation(sym);1021 struct annotation *notes = symbol__annotation(sym);
1022 struct annotated_branch *branch;
964 1023
965 if (notes->src == NULL) {1024 branch = annotation__get_branch(notes);
966 notes->src = annotated_source__new();1025 if (branch == NULL)
967 if (notes->src == NULL)1026 return NULL;
968 return NULL;1027
969 goto alloc_cycles_hist;1028 if (branch->cycles_hist == NULL) {
970 }1029 const size_t size = symbol__size(sym);
971 1030
972 if (!notes->src->cycles_hist) {1031 branch->cycles_hist = calloc(size, sizeof(struct cyc_hist));
973alloc_cycles_hist:
974 symbol__alloc_hist_cycles(sym);
975 }1032 }
976 1033
977 return notes->src->cycles_hist;1034 return branch->cycles_hist;
978}1035}
979 1036
980struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)1037struct 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
1077 u64 offset;1134 u64 offset;
1078 1135
1079 for (offset = start; offset <= end; offset++) {1136 for (offset = start; offset <= end; offset++) {
1080 if (notes->offsets[offset])1137 if (notes->src->offsets[offset])
1081 n_insn++;1138 n_insn++;
1082 }1139 }
1083 return n_insn;1140 return n_insn;
1084}1141}
1085 1142
1143static void annotated_branch__delete(struct annotated_branch *branch)
1144{
1145 if (branch) {
1146 zfree(&branch->cycles_hist);
1147 free(branch);
1148 }
1149}
1150
1086static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)1151static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)
1087{1152{
1088 unsigned n_insn;1153 unsigned n_insn;
@@ -1091,6 +1156,7 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 · 2 unmodified lines
1091 1156
1092 n_insn = annotation__count_insn(notes, start, end);1157 n_insn = annotation__count_insn(notes, start, end);
1093 if (n_insn && ch->num && ch->cycles) {1158 if (n_insn && ch->num && ch->cycles) {
1159 struct annotated_branch *branch;
1094 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);1160 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
1095 1161
1096 /* Hide data when there are too many overlaps. */1162 /* 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
1098 return;1164 return;
1099 1165
1100 for (offset = start; offset <= end; offset++) {1166 for (offset = start; offset <= end; offset++) {
1101 struct annotation_line *al = notes->offsets[offset];1167 struct annotation_line *al = notes->src->offsets[offset];
1102 1168
1103 if (al && al->ipc == 0.0) {1169 if (al && al->cycles && al->cycles->ipc == 0.0) {
1104 al->ipc = ipc;1170 al->cycles->ipc = ipc;
1105 cover_insn++;1171 cover_insn++;
1106 }1172 }
1107 }1173 }
1108 1174
1109 if (cover_insn) {1175 branch = annotation__get_branch(notes);
1110 notes->hit_cycles += ch->cycles;1176 if (cover_insn && branch) {
1111 notes->hit_insn += n_insn * ch->num;1177 branch->hit_cycles += ch->cycles;
1112 notes->cover_insn += cover_insn;1178 branch->hit_insn += n_insn * ch->num;
1179 branch->cover_insn += cover_insn;
1113 }1180 }
1114 }1181 }
1115}1182}
1116 1183
1117void annotation__compute_ipc(struct annotation *notes, size_t size)1184static int annotation__compute_ipc(struct annotation *notes, size_t size)
1118{1185{
1186 int err = 0;
1119 s64 offset;1187 s64 offset;
1120 1188
1121 if (!notes->src || !notes->src->cycles_hist)1189 if (!notes->branch || !notes->branch->cycles_hist)
1122 return;1190 return 0;
1123 1191
1124 notes->total_insn = annotation__count_insn(notes, 0, size - 1);1192 notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1);
1125 notes->hit_cycles = 0;1193 notes->branch->hit_cycles = 0;
1126 notes->hit_insn = 0;1194 notes->branch->hit_insn = 0;
1127 notes->cover_insn = 0;1195 notes->branch->cover_insn = 0;
1128 1196
1129 annotation__lock(notes);1197 annotation__lock(notes);
1130 for (offset = size - 1; offset >= 0; --offset) {1198 for (offset = size - 1; offset >= 0; --offset) {
1131 struct cyc_hist *ch;1199 struct cyc_hist *ch;
1132 1200
1133 ch = &notes->src->cycles_hist[offset];1201 ch = &notes->branch->cycles_hist[offset];
1134 if (ch && ch->cycles) {1202 if (ch && ch->cycles) {
1135 struct annotation_line *al;1203 struct annotation_line *al;
1136 1204
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 }
1137 if (ch->have_start)1213 if (ch->have_start)
1138 annotation__count_and_fill(notes, ch->start, offset, ch);1214 annotation__count_and_fill(notes, ch->start, offset, ch);
1139 al = notes->offsets[offset];
1140 if (al && ch->num_aggr) {1215 if (al && ch->num_aggr) {
1141 al->cycles = ch->cycles_aggr / ch->num_aggr;1216 al->cycles->avg = ch->cycles_aggr / ch->num_aggr;
1142 al->cycles_max = ch->cycles_max;1217 al->cycles->max = ch->cycles_max;
1143 al->cycles_min = ch->cycles_min;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);
1144 }1231 }
1145 notes->have_cycles = true;
1146 }1232 }
1147 }1233 }
1234
1148 annotation__unlock(notes);1235 annotation__unlock(notes);
1236 return 0;
1149}1237}
1150 1238
1151int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,1239int 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
1225{1313{
1226 zfree_srcline(&al->path);1314 zfree_srcline(&al->path);
1227 zfree(&al->line);1315 zfree(&al->line);
1316 zfree(&al->cycles);
1228}1317}
1229 1318
1230static size_t disasm_line_size(int nr)1319static 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
1299void annotation__exit(struct annotation *notes)1388void annotation__exit(struct annotation *notes)
1300{1389{
1301 annotated_source__delete(notes->src);1390 annotated_source__delete(notes->src);
1391 annotated_branch__delete(notes->branch);
1302}1392}
1303 1393
1304static struct sharded_mutex *sharded_mutex;1394static struct sharded_mutex *sharded_mutex;
@@ -1817,7 +1907,6 @@ static int symbol__disassemble_bpf(struct symbol *sym, · 512 unmodified lines
1817 struct annotate_args *args)1907 struct annotate_args *args)
1818{1908{
1819 struct annotation *notes = symbol__annotation(sym);1909 struct annotation *notes = symbol__annotation(sym);
1820 struct annotation_options *opts = args->options;
1821 struct bpf_prog_linfo *prog_linfo = NULL;1910 struct bpf_prog_linfo *prog_linfo = NULL;
1822 struct bpf_prog_info_node *info_node;1911 struct bpf_prog_info_node *info_node;
1823 int len = sym->end - sym->start;1912 int len = sym->end - sym->start;
@@ -1927,7 +2016,7 @@ static int symbol__disassemble_bpf(struct symbol *sym, · 103 unmodified lines
1927 prev_buf_size = buf_size;2016 prev_buf_size = buf_size;
1928 fflush(s);2017 fflush(s);
1929 2018
1930 if (!opts->hide_src_code && srcline) {2019 if (!annotate_opts.hide_src_code && srcline) {
1931 args->offset = -1;2020 args->offset = -1;
1932 args->line = strdup(srcline);2021 args->line = strdup(srcline);
1933 args->line_nr = 0;2022 args->line_nr = 0;
@@ -2050,7 +2139,7 @@ static char *expand_tabs(char *line, char **storage, size_t *storage_len) · 116 unmodified lines
2050 2139
2051static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)2140static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
2052{2141{
2053 struct annotation_options *opts = args->options;2142 struct annotation_options *opts = &annotate_opts;
2054 struct map *map = args->ms.map;2143 struct map *map = args->ms.map;
2055 struct dso *dso = map__dso(map);2144 struct dso *dso = map__dso(map);
2056 char *command;2145 char *command;
@@ -2113,12 +2202,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) · 56 unmodified lines
2113 err = asprintf(&command,2202 err = asprintf(&command,
2114 "%s %s%s --start-address=0x%016" PRIx642203 "%s %s%s --start-address=0x%016" PRIx64
2115 " --stop-address=0x%016" PRIx642204 " --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\"",
2117 opts->objdump_path ?: "objdump",2206 opts->objdump_path ?: "objdump",
2118 opts->disassembler_style ? "-M " : "",2207 opts->disassembler_style ? "-M " : "",
2119 opts->disassembler_style ?: "",2208 opts->disassembler_style ?: "",
2120 map__rip_2objdump(map, sym->start),2209 map__rip_2objdump(map, sym->start),
2121 map__rip_2objdump(map, sym->end),2210 map__rip_2objdump(map, sym->end),
2211 opts->show_linenr ? "-l" : "",
2122 opts->show_asm_raw ? "" : "--no-show-raw-insn",2212 opts->show_asm_raw ? "" : "--no-show-raw-insn",
2123 opts->annotate_src ? "-S" : "",2213 opts->annotate_src ? "-S" : "",
2124 opts->prefix ? "--prefix " : "",2214 opts->prefix ? "--prefix " : "",
@@ -2299,15 +2389,8 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) · 174 unmodified lines
2299 annotation__calc_percent(notes, evsel, symbol__size(sym));2389 annotation__calc_percent(notes, evsel, symbol__size(sym));
2300}2390}
2301 2391
2302int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,2392static int evsel__get_arch(struct evsel *evsel, struct arch **parch)
2303 struct annotation_options *options, struct arch **parch)
2304{2393{
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 };
2311 struct perf_env *env = evsel__env(evsel);2394 struct perf_env *env = evsel__env(evsel);
2312 const char *arch_name = perf_env__arch(env);2395 const char *arch_name = perf_env__arch(env);
2313 struct arch *arch;2396 struct arch *arch;
@@ -2316,25 +2399,45 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, · 2 unmodified lines
2316 if (!arch_name)2399 if (!arch_name)
2317 return errno;2400 return errno;
2318 2401
2319 args.arch = arch = arch__find(arch_name);2402 *parch = arch = arch__find(arch_name);
2320 if (arch == NULL) {2403 if (arch == NULL) {
2321 pr_err("%s: unsupported arch %s\n", __func__, arch_name);2404 pr_err("%s: unsupported arch %s\n", __func__, arch_name);
2322 return ENOTSUP;2405 return ENOTSUP;
2323 }2406 }
2324 2407
2325 if (parch)
2326 *parch = arch;
2327
2328 if (arch->init) {2408 if (arch->init) {
2329 err = arch->init(arch, env ? env->cpuid : NULL);2409 err = arch->init(arch, env ? env->cpuid : NULL);
2330 if (err) {2410 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);
2332 return err;2413 return err;
2333 }2414 }
2334 }2415 }
2416 return 0;
2417}
2335 2418
2419int 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;
2336 args.ms = *ms;2439 args.ms = *ms;
2337 if (notes->options && notes->options->full_addr)2440 if (annotate_opts.full_addr)
2338 notes->start = map__objdump_2mem(ms->map, ms->sym->start);2441 notes->start = map__objdump_2mem(ms->map, ms->sym->start);
2339 else2442 else
2340 notes->start = map__rip_2objdump(ms->map, ms->sym->start);2443 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
2342 return symbol__disassemble(sym, &args);2445 return symbol__disassemble(sym, &args);
2343}2446}
2344 2447
2345static void insert_source_line(struct rb_root *root, struct annotation_line *al,2448static void insert_source_line(struct rb_root *root, struct annotation_line *al)
2346 struct annotation_options *opts)
2347{2449{
2348 struct annotation_line *iter;2450 struct annotation_line *iter;
2349 struct rb_node **p = &root->rb_node;2451 struct rb_node **p = &root->rb_node;
2350 struct rb_node *parent = NULL;2452 struct rb_node *parent = NULL;
2453 unsigned int percent_type = annotate_opts.percent_type;
2351 int i, ret;2454 int i, ret;
2352 2455
2353 while (*p != NULL) {2456 while (*p != NULL) {
@@ -2358,7 +2461,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, · 4 unmodified lines
2358 if (ret == 0) {2461 if (ret == 0) {
2359 for (i = 0; i < al->data_nr; i++) {2462 for (i = 0; i < al->data_nr; i++) {
2360 iter->data[i].percent_sum += annotation_data__percent(&al->data[i],2463 iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
2361 opts->percent_type);2464 percent_type);
2362 }2465 }
2363 return;2466 return;
2364 }2467 }
@@ -2371,7 +2474,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, · 6 unmodified lines
2371 2474
2372 for (i = 0; i < al->data_nr; i++) {2475 for (i = 0; i < al->data_nr; i++) {
2373 al->data[i].percent_sum = annotation_data__percent(&al->data[i],2476 al->data[i].percent_sum = annotation_data__percent(&al->data[i],
2374 opts->percent_type);2477 percent_type);
2375 }2478 }
2376 2479
2377 rb_link_node(&al->rb_node, parent, p);2480 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
2493 return 0;2596 return 0;
2494}2597}
2495 2598
2496int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,2599int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel)
2497 struct annotation_options *opts)
2498{2600{
2499 struct map *map = ms->map;2601 struct map *map = ms->map;
2500 struct symbol *sym = ms->sym;2602 struct symbol *sym = ms->sym;
@@ -2505,6 +2607,7 @@ int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, · 4 unmodified lines
2505 struct annotation *notes = symbol__annotation(sym);2607 struct annotation *notes = symbol__annotation(sym);
2506 struct sym_hist *h = annotation__histogram(notes, evsel->core.idx);2608 struct sym_hist *h = annotation__histogram(notes, evsel->core.idx);
2507 struct annotation_line *pos, *queue = NULL;2609 struct annotation_line *pos, *queue = NULL;
2610 struct annotation_options *opts = &annotate_opts;
2508 u64 start = map__rip_2objdump(map, sym->start);2611 u64 start = map__rip_2objdump(map, sym->start);
2509 int printed = 2, queue_len = 0, addr_fmt_width;2612 int printed = 2, queue_len = 0, addr_fmt_width;
2510 int more = 0;2613 int more = 0;
@@ -2633,8 +2736,7 @@ static void FILE__write_graph(void *fp, int graph) · 122 unmodified lines
2633 fputs(s, fp);2736 fputs(s, fp);
2634}2737}
2635 2738
2636static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,2739static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp)
2637 struct annotation_options *opts)
2638{2740{
2639 struct annotation *notes = symbol__annotation(sym);2741 struct annotation *notes = symbol__annotation(sym);
2640 struct annotation_write_ops wops = {2742 struct annotation_write_ops wops = {
@@ -2649,9 +2751,9 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, · 8 unmodified lines
2649 struct annotation_line *al;2751 struct annotation_line *al;
2650 2752
2651 list_for_each_entry(al, &notes->src->source, node) {2753 list_for_each_entry(al, &notes->src->source, node) {
2652 if (annotation_line__filter(al, notes))2754 if (annotation_line__filter(al))
2653 continue;2755 continue;
2654 annotation_line__write(al, notes, &wops, opts);2756 annotation_line__write(al, notes, &wops);
2655 fputc('\n', fp);2757 fputc('\n', fp);
2656 wops.first_line = false;2758 wops.first_line = false;
2657 }2759 }
@@ -2659,8 +2761,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, · 1 unmodified line
2659 return 0;2761 return 0;
2660}2762}
2661 2763
2662int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,2764int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel)
2663 struct annotation_options *opts)
2664{2765{
2665 const char *ev_name = evsel__name(evsel);2766 const char *ev_name = evsel__name(evsel);
2666 char buf[1024];2767 char buf[1024];
@@ -2682,7 +2783,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, · 15 unmodified lines
2682 2783
2683 fprintf(fp, "%s() %s\nEvent: %s\n\n",2784 fprintf(fp, "%s() %s\nEvent: %s\n\n",
2684 ms->sym->name, map__dso(ms->map)->long_name, ev_name);2785 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);
2686 2787
2687 fclose(fp);2788 fclose(fp);
2688 err = 0;2789 err = 0;
@@ -2769,7 +2870,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) · 80 unmodified lines
2769 return;2870 return;
2770 2871
2771 for (offset = 0; offset < size; ++offset) {2872 for (offset = 0; offset < size; ++offset) {
2772 struct annotation_line *al = notes->offsets[offset];2873 struct annotation_line *al = notes->src->offsets[offset];
2773 struct disasm_line *dl;2874 struct disasm_line *dl;
2774 2875
2775 dl = disasm_line(al);2876 dl = disasm_line(al);
@@ -2777,7 +2878,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) · 1 unmodified line
2777 if (!disasm_line__is_valid_local_jump(dl, sym))2878 if (!disasm_line__is_valid_local_jump(dl, sym))
2778 continue;2879 continue;
2779 2880
2780 al = notes->offsets[dl->ops.target.offset];2881 al = notes->src->offsets[dl->ops.target.offset];
2781 2882
2782 /*2883 /*
2783 * FIXME: Oops, no jump target? Buggy disassembler? Or do we2884 * 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
2794void annotation__set_offsets(struct annotation *notes, s64 size)2895void annotation__set_offsets(struct annotation *notes, s64 size)
2795{2896{
2796 struct annotation_line *al;2897 struct annotation_line *al;
2898 struct annotated_source *src = notes->src;
2797 2899
2798 notes->max_line_len = 0;2900 src->max_line_len = 0;
2799 notes->nr_entries = 0;2901 src->nr_entries = 0;
2800 notes->nr_asm_entries = 0;2902 src->nr_asm_entries = 0;
2801 2903
2802 list_for_each_entry(al, &notes->src->source, node) {2904 list_for_each_entry(al, &src->source, node) {
2803 size_t line_len = strlen(al->line);2905 size_t line_len = strlen(al->line);
2804 2906
2805 if (notes->max_line_len < line_len)2907 if (src->max_line_len < line_len)
2806 notes->max_line_len = line_len;2908 src->max_line_len = line_len;
2807 al->idx = notes->nr_entries++;2909 al->idx = src->nr_entries++;
2808 if (al->offset != -1) {2910 if (al->offset != -1) {
2809 al->idx_asm = notes->nr_asm_entries++;2911 al->idx_asm = src->nr_asm_entries++;
2810 /*2912 /*
2811 * FIXME: short term bandaid to cope with assembly2913 * FIXME: short term bandaid to cope with assembly
2812 * routines that comes with labels in the same column2914 * 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
2815 * E.g. copy_user_generic_unrolled2917 * E.g. copy_user_generic_unrolled
2816 */2918 */
2817 if (al->offset < size)2919 if (al->offset < size)
2818 notes->offsets[al->offset] = al;2920 notes->src->offsets[al->offset] = al;
2819 } else2921 } else
2820 al->idx_asm = -1;2922 al->idx_asm = -1;
2821 }2923 }
@@ -2858,24 +2960,24 @@ void annotation__init_column_widths(struct annotation *notes, struct symbol *sym · 36 unmodified lines
2858 2960
2859void annotation__update_column_widths(struct annotation *notes)2961void annotation__update_column_widths(struct annotation *notes)
2860{2962{
2861 if (notes->options->use_offset)2963 if (annotate_opts.use_offset)
2862 notes->widths.target = notes->widths.min_addr;2964 notes->widths.target = notes->widths.min_addr;
2863 else if (notes->options->full_addr)2965 else if (annotate_opts.full_addr)
2864 notes->widths.target = BITS_PER_LONG / 4;2966 notes->widths.target = BITS_PER_LONG / 4;
2865 else2967 else
2866 notes->widths.target = notes->widths.max_addr;2968 notes->widths.target = notes->widths.max_addr;
2867 2969
2868 notes->widths.addr = notes->widths.target;2970 notes->widths.addr = notes->widths.target;
2869 2971
2870 if (notes->options->show_nr_jumps)2972 if (annotate_opts.show_nr_jumps)
2871 notes->widths.addr += notes->widths.jumps + 1;2973 notes->widths.addr += notes->widths.jumps + 1;
2872}2974}
2873 2975
2874void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms)2976void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms)
2875{2977{
2876 notes->options->full_addr = !notes->options->full_addr;2978 annotate_opts.full_addr = !annotate_opts.full_addr;
2877 2979
2878 if (notes->options->full_addr)2980 if (annotate_opts.full_addr)
2879 notes->start = map__objdump_2mem(ms->map, ms->sym->start);2981 notes->start = map__objdump_2mem(ms->map, ms->sym->start);
2880 else2982 else
2881 notes->start = map__rip_2objdump(ms->map, ms->sym->start);2983 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
2884}2986}
2885 2987
2886static void annotation__calc_lines(struct annotation *notes, struct map *map,2988static void annotation__calc_lines(struct annotation *notes, struct map *map,
2887 struct rb_root *root,2989 struct rb_root *root)
2888 struct annotation_options *opts)
2889{2990{
2890 struct annotation_line *al;2991 struct annotation_line *al;
2891 struct rb_root tmp_root = RB_ROOT;2992 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
2898 double percent;2999 double percent;
2899 3000
2900 percent = annotation_data__percent(&al->data[i],3001 percent = annotation_data__percent(&al->data[i],
2901 opts->percent_type);3002 annotate_opts.percent_type);
2902 3003
2903 if (percent > percent_max)3004 if (percent > percent_max)
2904 percent_max = percent;3005 percent_max = percent;
@@ -2909,22 +3010,20 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, · 4 unmodified lines
2909 3010
2910 al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL,3011 al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL,
2911 false, true, notes->start + al->offset);3012 false, true, notes->start + al->offset);
2912 insert_source_line(&tmp_root, al, opts);3013 insert_source_line(&tmp_root, al);
2913 }3014 }
2914 3015
2915 resort_source_line(root, &tmp_root);3016 resort_source_line(root, &tmp_root);
2916}3017}
2917 3018
2918static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root,3019static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root)
2919 struct annotation_options *opts)
2920{3020{
2921 struct annotation *notes = symbol__annotation(ms->sym);3021 struct annotation *notes = symbol__annotation(ms->sym);
2922 3022
2923 annotation__calc_lines(notes, ms->map, root, opts);3023 annotation__calc_lines(notes, ms->map, root);
2924}3024}
2925 3025
2926int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel,3026int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel)
2927 struct annotation_options *opts)
2928{3027{
2929 struct dso *dso = map__dso(ms->map);3028 struct dso *dso = map__dso(ms->map);
2930 struct symbol *sym = ms->sym;3029 struct symbol *sym = ms->sym;
@@ -2933,7 +3032,7 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, · 2 unmodified lines
2933 char buf[1024];3032 char buf[1024];
2934 int err;3033 int err;
2935 3034
2936 err = symbol__annotate2(ms, evsel, opts, NULL);3035 err = symbol__annotate2(ms, evsel, NULL);
2937 if (err) {3036 if (err) {
2938 char msg[BUFSIZ];3037 char msg[BUFSIZ];
2939 3038
@@ -2943,31 +3042,31 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, · 3 unmodified lines
2943 return -1;3042 return -1;
2944 }3043 }
2945 3044
2946 if (opts->print_lines) {3045 if (annotate_opts.print_lines) {
2947 srcline_full_filename = opts->full_path;3046 srcline_full_filename = annotate_opts.full_path;
2948 symbol__calc_lines(ms, &source_line, opts);3047 symbol__calc_lines(ms, &source_line);
2949 print_summary(&source_line, dso->long_name);3048 print_summary(&source_line, dso->long_name);
2950 }3049 }
2951 3050
2952 hists__scnprintf_title(hists, buf, sizeof(buf));3051 hists__scnprintf_title(hists, buf, sizeof(buf));
2953 fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",3052 fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
2954 buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);3053 buf, percent_type_str(annotate_opts.percent_type), sym->name,
2955 symbol__annotate_fprintf2(sym, stdout, opts);3054 dso->long_name);
3055 symbol__annotate_fprintf2(sym, stdout);
2956 3056
2957 annotated_source__purge(symbol__annotation(sym)->src);3057 annotated_source__purge(symbol__annotation(sym)->src);
2958 3058
2959 return 0;3059 return 0;
2960}3060}
2961 3061
2962int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,3062int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel)
2963 struct annotation_options *opts)
2964{3063{
2965 struct dso *dso = map__dso(ms->map);3064 struct dso *dso = map__dso(ms->map);
2966 struct symbol *sym = ms->sym;3065 struct symbol *sym = ms->sym;
2967 struct rb_root source_line = RB_ROOT;3066 struct rb_root source_line = RB_ROOT;
2968 int err;3067 int err;
2969 3068
2970 err = symbol__annotate(ms, evsel, opts, NULL);3069 err = symbol__annotate(ms, evsel, NULL);
2971 if (err) {3070 if (err) {
2972 char msg[BUFSIZ];3071 char msg[BUFSIZ];
2973 3072
@@ -2979,13 +3078,13 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, · 5 unmodified lines
2979 3078
2980 symbol__calc_percent(sym, evsel);3079 symbol__calc_percent(sym, evsel);
2981 3080
2982 if (opts->print_lines) {3081 if (annotate_opts.print_lines) {
2983 srcline_full_filename = opts->full_path;3082 srcline_full_filename = annotate_opts.full_path;
2984 symbol__calc_lines(ms, &source_line, opts);3083 symbol__calc_lines(ms, &source_line);
2985 print_summary(&source_line, dso->long_name);3084 print_summary(&source_line, dso->long_name);
2986 }3085 }
2987 3086
2988 symbol__annotate_printf(ms, evsel, opts);3087 symbol__annotate_printf(ms, evsel);
2989 3088
2990 annotated_source__purge(symbol__annotation(sym)->src);3089 annotated_source__purge(symbol__annotation(sym)->src);
2991 3090
@@ -3046,19 +3145,20 @@ call_like: · 54 unmodified lines
3046 obj__printf(obj, " ");3145 obj__printf(obj, " ");
3047 }3146 }
3048 3147
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);
3050}3149}
3051 3150
3052static void ipc_coverage_string(char *bf, int size, struct annotation *notes)3151static void ipc_coverage_string(char *bf, int size, struct annotation *notes)
3053{3152{
3054 double ipc = 0.0, coverage = 0.0;3153 double ipc = 0.0, coverage = 0.0;
3154 struct annotated_branch *branch = annotation__get_branch(notes);
3055 3155
3056 if (notes->hit_cycles)3156 if (branch && branch->hit_cycles)
3057 ipc = notes->hit_insn / ((double)notes->hit_cycles);3157 ipc = branch->hit_insn / ((double)branch->hit_cycles);
3058 3158
3059 if (notes->total_insn) {3159 if (branch && branch->total_insn) {
3060 coverage = notes->cover_insn * 100.0 /3160 coverage = branch->cover_insn * 100.0 /
3061 ((double)notes->total_insn);3161 ((double)branch->total_insn);
3062 }3162 }
3063 3163
3064 scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",3164 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
3083 int printed;3183 int printed;
3084 3184
3085 if (first_line && (al->offset == -1 || percent_max == 0.0)) {3185 if (first_line && (al->offset == -1 || percent_max == 0.0)) {
3086 if (notes->have_cycles) {3186 if (notes->branch && al->cycles) {
3087 if (al->ipc == 0.0 && al->cycles == 0)3187 if (al->cycles->ipc == 0.0 && al->cycles->avg == 0)
3088 show_title = true;3188 show_title = true;
3089 } else3189 } else
3090 show_title = true;3190 show_title = true;
@@ -3120,18 +3220,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 29 unmodified lines
3120 }3220 }
3121 }3221 }
3122 3222
3123 if (notes->have_cycles) {3223 if (notes->branch) {
3124 if (al->ipc)3224 if (al->cycles && al->cycles->ipc)
3125 obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);3225 obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->cycles->ipc);
3126 else if (!show_title)3226 else if (!show_title)
3127 obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " ");3227 obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " ");
3128 else3228 else
3129 obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");3229 obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
3130 3230
3131 if (!notes->options->show_minmax_cycle) {3231 if (!annotate_opts.show_minmax_cycle) {
3132 if (al->cycles)3232 if (al->cycles && al->cycles->avg)
3133 obj__printf(obj, "%*" PRIu64 " ",3233 obj__printf(obj, "%*" PRIu64 " ",
3134 ANNOTATION__CYCLES_WIDTH - 1, al->cycles);3234 ANNOTATION__CYCLES_WIDTH - 1, al->cycles->avg);
3135 else if (!show_title)3235 else if (!show_title)
3136 obj__printf(obj, "%*s",3236 obj__printf(obj, "%*s",
3137 ANNOTATION__CYCLES_WIDTH, " ");3237 ANNOTATION__CYCLES_WIDTH, " ");
@@ -3145,8 +3245,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 7 unmodified lines
3145 3245
3146 scnprintf(str, sizeof(str),3246 scnprintf(str, sizeof(str),
3147 "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",3247 "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",
3148 al->cycles, al->cycles_min,3248 al->cycles->avg, al->cycles->min,
3149 al->cycles_max);3249 al->cycles->max);
3150 3250
3151 obj__printf(obj, "%*s ",3251 obj__printf(obj, "%*s ",
3152 ANNOTATION__MINMAX_CYCLES_WIDTH - 1,3252 ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
@@ -3172,7 +3272,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 19 unmodified lines
3172 if (!*al->line)3272 if (!*al->line)
3173 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " ");3273 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " ");
3174 else if (al->offset == -1) {3274 else if (al->offset == -1) {
3175 if (al->line_nr && notes->options->show_linenr)3275 if (al->line_nr && annotate_opts.show_linenr)
3176 printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr);3276 printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr);
3177 else3277 else
3178 printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " ");3278 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
3182 u64 addr = al->offset;3282 u64 addr = al->offset;
3183 int color = -1;3283 int color = -1;
3184 3284
3185 if (!notes->options->use_offset)3285 if (!annotate_opts.use_offset)
3186 addr += notes->start;3286 addr += notes->start;
3187 3287
3188 if (!notes->options->use_offset) {3288 if (!annotate_opts.use_offset) {
3189 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);3289 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
3190 } else {3290 } else {
3191 if (al->jump_sources &&3291 if (al->jump_sources &&
3192 notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {3292 annotate_opts.offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {
3193 if (notes->options->show_nr_jumps) {3293 if (annotate_opts.show_nr_jumps) {
3194 int prev;3294 int prev;
3195 printed = scnprintf(bf, sizeof(bf), "%*d ",3295 printed = scnprintf(bf, sizeof(bf), "%*d ",
3196 notes->widths.jumps,3296 notes->widths.jumps,
@@ -3204,9 +3304,9 @@ print_addr: · 7 unmodified lines
3204 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",3304 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
3205 notes->widths.target, addr);3305 notes->widths.target, addr);
3206 } else if (ins__is_call(&disasm_line(al)->ins) &&3306 } 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) {
3208 goto print_addr;3308 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) {
3210 goto print_addr;3310 goto print_addr;
3211 } else {3311 } else {
3212 printed = scnprintf(bf, sizeof(bf), "%-*s ",3312 printed = scnprintf(bf, sizeof(bf), "%-*s ",
@@ -3228,43 +3328,44 @@ print_addr: · 15 unmodified lines
3228}3328}
3229 3329
3230void annotation_line__write(struct annotation_line *al, struct annotation *notes,3330void annotation_line__write(struct annotation_line *al, struct annotation *notes,
3231 struct annotation_write_ops *wops,3331 struct annotation_write_ops *wops)
3232 struct annotation_options *opts)
3233{3332{
3234 __annotation_line__write(al, notes, wops->first_line, wops->current_entry,3333 __annotation_line__write(al, notes, wops->first_line, wops->current_entry,
3235 wops->change_color, wops->width, wops->obj,3334 wops->change_color, wops->width, wops->obj,
3236 opts->percent_type,3335 annotate_opts.percent_type,
3237 wops->set_color, wops->set_percent_color,3336 wops->set_color, wops->set_percent_color,
3238 wops->set_jumps_percent_color, wops->printf,3337 wops->set_jumps_percent_color, wops->printf,
3239 wops->write_graph);3338 wops->write_graph);
3240}3339}
3241 3340
3242int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,3341int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
3243 struct annotation_options *options, struct arch **parch)3342 struct arch **parch)
3244{3343{
3245 struct symbol *sym = ms->sym;3344 struct symbol *sym = ms->sym;
3246 struct annotation *notes = symbol__annotation(sym);3345 struct annotation *notes = symbol__annotation(sym);
3247 size_t size = symbol__size(sym);3346 size_t size = symbol__size(sym);
3248 int nr_pcnt = 1, err;3347 int nr_pcnt = 1, err;
3249 3348
3250 notes->offsets = zalloc(size * sizeof(struct annotation_line *));3349 notes->src->offsets = zalloc(size * sizeof(struct annotation_line *));
3251 if (notes->offsets == NULL)3350 if (notes->src->offsets == NULL)
3252 return ENOMEM;3351 return ENOMEM;
3253 3352
3254 if (evsel__is_group_event(evsel))3353 if (evsel__is_group_event(evsel))
3255 nr_pcnt = evsel->core.nr_members;3354 nr_pcnt = evsel->core.nr_members;
3256 3355
3257 err = symbol__annotate(ms, evsel, options, parch);3356 err = symbol__annotate(ms, evsel, parch);
3258 if (err)3357 if (err)
3259 goto out_free_offsets;3358 goto out_free_offsets;
3260 3359
3261 notes->options = options;
3262
3263 symbol__calc_percent(sym, evsel);3360 symbol__calc_percent(sym, evsel);
3264 3361
3265 annotation__set_offsets(notes, size);3362 annotation__set_offsets(notes, size);
3266 annotation__mark_jump_targets(notes, sym);3363 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
3268 annotation__init_column_widths(notes, sym);3369 annotation__init_column_widths(notes, sym);
3269 notes->nr_events = nr_pcnt;3370 notes->nr_events = nr_pcnt;
3270 3371
@@ -3274,7 +3375,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, · 3 unmodified lines
3274 return 0;3375 return 0;
3275 3376
3276out_free_offsets:3377out_free_offsets:
3277 zfree(&notes->offsets);3378 zfree(&notes->src->offsets);
3278 return err;3379 return err;
3279}3380}
3280 3381
@@ -3337,8 +3438,10 @@ static int annotation__config(const char *var, const char *value, void *data) · 56 unmodified lines
3337 return 0;3438 return 0;
3338}3439}
3339 3440
3340void annotation_options__init(struct annotation_options *opt)3441void annotation_options__init(void)
3341{3442{
3443 struct annotation_options *opt = &annotate_opts;
3444
3342 memset(opt, 0, sizeof(*opt));3445 memset(opt, 0, sizeof(*opt));
3343 3446
3344 /* Default values. */3447 /* Default values. */
@@ -3349,16 +3452,15 @@ void annotation_options__init(struct annotation_options *opt) · 4 unmodified lines
3349 opt->percent_type = PERCENT_PERIOD_LOCAL;3452 opt->percent_type = PERCENT_PERIOD_LOCAL;
3350}3453}
3351 3454
3352 3455void annotation_options__exit(void)
3353void annotation_options__exit(struct annotation_options *opt)
3354{3456{
3355 zfree(&opt->disassembler_style);3457 zfree(&annotate_opts.disassembler_style);
3356 zfree(&opt->objdump_path);3458 zfree(&annotate_opts.objdump_path);
3357}3459}
3358 3460
3359void annotation_config__init(struct annotation_options *opt)3461void annotation_config__init(void)
3360{3462{
3361 perf_config(annotation__config, opt);3463 perf_config(annotation__config, &annotate_opts);
3362}3464}
3363 3465
3364static unsigned int parse_percent_type(char *str1, char *str2)3466static 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
3382 return type;3484 return type;
3383}3485}
3384 3486
3385int annotate_parse_percent_type(const struct option *opt, const char *_str,3487int annotate_parse_percent_type(const struct option *opt __maybe_unused, const char *_str,
3386 int unset __maybe_unused)3488 int unset __maybe_unused)
3387{3489{
3388 struct annotation_options *opts = opt->value;
3389 unsigned int type;3490 unsigned int type;
3390 char *str1, *str2;3491 char *str1, *str2;
3391 int err = -1;3492 int err = -1;
@@ -3404,7 +3505,7 @@ int annotate_parse_percent_type(const struct option *opt, const char *_str, · 12 unmodified lines
3404 if (type == (unsigned int) -1)3505 if (type == (unsigned int) -1)
3405 type = parse_percent_type(str2, str1);3506 type = parse_percent_type(str2, str1);
3406 if (type != (unsigned int) -1) {3507 if (type != (unsigned int) -1) {
3407 opts->percent_type = type;3508 annotate_opts.percent_type = type;
3408 err = 0;3509 err = 0;
3409 }3510 }
3410 3511
@@ -3413,11 +3514,267 @@ out: · 2 unmodified lines
3413 return err;3514 return err;
3414}3515}
3415 3516
3416int annotate_check_args(struct annotation_options *args)3517int annotate_check_args(void)
3417{3518{
3519 struct annotation_options *args = &annotate_opts;
3520
3418 if (args->prefix_strip && !args->prefix) {3521 if (args->prefix_strip && !args->prefix) {
3419 pr_err("--prefix-strip requires --prefix\n");3522 pr_err("--prefix-strip requires --prefix\n");
3420 return -1;3523 return -1;
3421 }3524 }
3422 return 0;3525 return 0;
3423}3526}
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 */
3534static 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 */
3589int 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
3634static 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
3655static 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
3669static 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 */
3702struct 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
23struct perf_sample;23struct perf_sample;
24struct evsel;24struct evsel;
25struct symbol;25struct symbol;
26struct annotated_data_type;
26 27
27struct ins {28struct ins {
28 const char *name;29 const char *name;
@@ -31,8 +32,6 @@ struct ins { · 2 unmodified lines
31 32
32struct ins_operands {33struct ins_operands {
33 char *raw;34 char *raw;
34 char *raw_comment;
35 char *raw_func_start;
36 struct {35 struct {
37 char *raw;36 char *raw;
38 char *name;37 char *name;
@@ -41,22 +40,30 @@ struct ins_operands { · 2 unmodified lines
41 s64 offset;40 s64 offset;
42 bool offset_avail;41 bool offset_avail;
43 bool outside;42 bool outside;
43 bool multi_regs;
44 } target;44 } target;
45 union {45 union {
46 struct {46 struct {
47 char *raw;47 char *raw;
48 char *name;48 char *name;
49 u64 addr;49 u64 addr;
50 bool multi_regs;
50 } source;51 } source;
51 struct {52 struct {
52 struct ins ins;53 struct ins ins;
53 struct ins_operands *ops;54 struct ins_operands *ops;
54 } locked;55 } locked;
56 struct {
57 char *raw_comment;
58 char *raw_func_start;
59 } jump;
55 };60 };
56};61};
57 62
58struct arch;63struct arch;
59 64
65bool arch__is(struct arch *arch, const char *name);
66
60struct ins_ops {67struct ins_ops {
61 void (*free)(struct ins_operands *ops);68 void (*free)(struct ins_operands *ops);
62 int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms);69 int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms);
@@ -101,6 +108,8 @@ struct annotation_options { · 38 unmodified lines
101 unsigned int percent_type;108 unsigned int percent_type;
102};109};
103 110
111extern struct annotation_options annotate_opts;
112
104enum {113enum {
105 ANNOTATION__OFFSET_JUMP_TARGETS = 1,114 ANNOTATION__OFFSET_JUMP_TARGETS = 1,
106 ANNOTATION__OFFSET_CALL,115 ANNOTATION__OFFSET_CALL,
@@ -130,6 +139,13 @@ struct annotation_data { · 23 unmodified lines
130 struct sym_hist_entry he;139 struct sym_hist_entry he;
131};140};
132 141
142struct cycles_info {
143 float ipc;
144 u64 avg;
145 u64 max;
146 u64 min;
147};
148
133struct annotation_line {149struct annotation_line {
134 struct list_head node;150 struct list_head node;
135 struct rb_node rb_node;151 struct rb_node rb_node;
@@ -137,12 +153,9 @@ struct annotation_line { · 1 unmodified line
137 char *line;153 char *line;
138 int line_nr;154 int line_nr;
139 char *fileloc;155 char *fileloc;
140 int jump_sources;
141 float ipc;
142 u64 cycles;
143 u64 cycles_max;
144 u64 cycles_min;
145 char *path;156 char *path;
157 struct cycles_info *cycles;
158 int jump_sources;
146 u32 idx;159 u32 idx;
147 int idx_asm;160 int idx_asm;
148 int data_nr;161 int data_nr;
@@ -214,8 +227,7 @@ struct annotation_write_ops { · 65 unmodified lines
214};227};
215 228
216void annotation_line__write(struct annotation_line *al, struct annotation *notes,229void annotation_line__write(struct annotation_line *al, struct annotation *notes,
217 struct annotation_write_ops *ops,230 struct annotation_write_ops *ops);
218 struct annotation_options *opts);
219 231
220int __annotation__scnprintf_samples_period(struct annotation *notes,232int __annotation__scnprintf_samples_period(struct annotation *notes,
221 char *bf, size_t size,233 char *bf, size_t size,
@@ -264,27 +276,29 @@ struct cyc_hist { · 42 unmodified lines
264 * returns.276 * returns.
265 */277 */
266struct annotated_source {278struct annotated_source {
267 struct list_head source;279 struct list_head source;
268 int nr_histograms;280 size_t sizeof_sym_hist;
269 size_t sizeof_sym_hist;281 struct sym_hist *histograms;
270 struct cyc_hist *cycles_hist;282 struct annotation_line **offsets;
271 struct sym_hist *histograms;283 int nr_histograms;
284 int nr_entries;
285 int nr_asm_entries;
286 u16 max_line_len;
272};287};
273 288
274struct LOCKABLE annotation {289struct annotated_branch {
275 u64 max_coverage;
276 u64 start;
277 u64 hit_cycles;290 u64 hit_cycles;
278 u64 hit_insn;291 u64 hit_insn;
279 unsigned int total_insn;292 unsigned int total_insn;
280 unsigned int cover_insn;293 unsigned int cover_insn;
281 struct annotation_options *options;294 struct cyc_hist *cycles_hist;
282 struct annotation_line **offsets;295 u64 max_coverage;
296};
297
298struct LOCKABLE annotation {
299 u64 start;
283 int nr_events;300 int nr_events;
284 int max_jump_sources;301 int max_jump_sources;
285 int nr_entries;
286 int nr_asm_entries;
287 u16 max_line_len;
288 struct {302 struct {
289 u8 addr;303 u8 addr;
290 u8 jumps;304 u8 jumps;
@@ -293,8 +307,8 @@ struct LOCKABLE annotation { · 2 unmodified lines
293 u8 max_addr;307 u8 max_addr;
294 u8 max_ins_name;308 u8 max_ins_name;
295 } widths;309 } widths;
296 bool have_cycles;
297 struct annotated_source *src;310 struct annotated_source *src;
311 struct annotated_branch *branch;
298};312};
299 313
300static inline void annotation__init(struct annotation *notes __maybe_unused)314static 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
308 322
309static inline int annotation__cycles_width(struct annotation *notes)323static inline int annotation__cycles_width(struct annotation *notes)
310{324{
311 if (notes->have_cycles && notes->options->show_minmax_cycle)325 if (notes->branch && annotate_opts.show_minmax_cycle)
312 return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH;326 return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH;
313 327
314 return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;328 return notes->branch ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
315}329}
316 330
317static inline int annotation__pcnt_width(struct annotation *notes)331static inline int annotation__pcnt_width(struct annotation *notes)
@@ -319,13 +333,12 @@ static inline int annotation__pcnt_width(struct annotation *notes) · 1 unmodified line
319 return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;333 return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
320}334}
321 335
322static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)336static inline bool annotation_line__filter(struct annotation_line *al)
323{337{
324 return notes->options->hide_src_code && al->offset == -1;338 return annotate_opts.hide_src_code && al->offset == -1;
325}339}
326 340
327void annotation__set_offsets(struct annotation *notes, s64 size);341void annotation__set_offsets(struct annotation *notes, s64 size);
328void annotation__compute_ipc(struct annotation *notes, size_t size);
329void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym);342void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym);
330void annotation__update_column_widths(struct annotation *notes);343void annotation__update_column_widths(struct annotation *notes);
331void annotation__init_column_widths(struct annotation *notes, struct symbol *sym);344void 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
349int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,362int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
350 struct evsel *evsel);363 struct evsel *evsel);
351 364
365struct annotated_branch *annotation__get_branch(struct annotation *notes);
366
352int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,367int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
353 struct addr_map_symbol *start,368 struct addr_map_symbol *start,
354 unsigned cycles);369 unsigned cycles);
@@ -361,11 +376,9 @@ void symbol__annotate_zero_histograms(struct symbol *sym); · 6 unmodified lines
361 376
362int symbol__annotate(struct map_symbol *ms,377int symbol__annotate(struct map_symbol *ms,
363 struct evsel *evsel,378 struct evsel *evsel,
364 struct annotation_options *options,
365 struct arch **parch);379 struct arch **parch);
366int symbol__annotate2(struct map_symbol *ms,380int symbol__annotate2(struct map_symbol *ms,
367 struct evsel *evsel,381 struct evsel *evsel,
368 struct annotation_options *options,
369 struct arch **parch);382 struct arch **parch);
370 383
371enum symbol_disassemble_errno {384enum symbol_disassemble_errno {
@@ -392,43 +405,86 @@ enum symbol_disassemble_errno { · 20 unmodified lines
392 405
393int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen);406int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen);
394 407
395int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,408int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel);
396 struct annotation_options *options);
397void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);409void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
398void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);410void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
399void annotated_source__purge(struct annotated_source *as);411void annotated_source__purge(struct annotated_source *as);
400 412
401int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,413int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel);
402 struct annotation_options *opts);
403 414
404bool ui__has_annotation(void);415bool ui__has_annotation(void);
405 416
406int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts);417int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel);
407 418
408int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts);419int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel);
409 420
410#ifdef HAVE_SLANG_SUPPORT421#ifdef HAVE_SLANG_SUPPORT
411int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,422int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
412 struct hist_browser_timer *hbt,423 struct hist_browser_timer *hbt);
413 struct annotation_options *opts);
414#else424#else
415static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,425static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
416 struct evsel *evsel __maybe_unused,426 struct evsel *evsel __maybe_unused,
417 struct hist_browser_timer *hbt __maybe_unused,427 struct hist_browser_timer *hbt __maybe_unused)
418 struct annotation_options *opts __maybe_unused)
419{428{
420 return 0;429 return 0;
421}430}
422#endif431#endif
423 432
424void annotation_options__init(struct annotation_options *opt);433void annotation_options__init(void);
425void annotation_options__exit(struct annotation_options *opt);434void annotation_options__exit(void);
426 435
427void annotation_config__init(struct annotation_options *opt);436void annotation_config__init(void);
428 437
429int annotate_parse_percent_type(const struct option *opt, const char *_str,438int annotate_parse_percent_type(const struct option *opt, const char *_str,
430 int unset);439 int unset);
431 440
432int annotate_check_args(struct annotation_options *args);441int 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 */
449struct annotated_op_loc {
450 int reg;
451 int offset;
452 bool mem_ref;
453};
454
455enum 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 */
466struct 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 */
476int 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) */
480struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he);
481
482struct annotated_item_stat {
483 struct list_head list;
484 char *name;
485 int good;
486 int bad;
487};
488extern struct list_head ann_insn_stat;
433 489
434#endif /* __PERF_ANNOTATE_H */490#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
174 struct evlist *evlist,174 struct evlist *evlist,
175 struct evsel *evsel, int idx)175 struct evsel *evsel, int idx)
176{176{
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);
178 178
179 mp->mmap_needed = evsel->needs_auxtrace_mmap;179 mp->mmap_needed = evsel->needs_auxtrace_mmap;
180 180
@@ -648,7 +648,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, · 467 unmodified lines
648 648
649static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)649static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
650{650{
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);
652 652
653 if (per_cpu_mmaps) {653 if (per_cpu_mmaps) {
654 struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx);654 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
1638 case 'Z':1638 case 'Z':
1639 synth_opts->timeless_decoding = true;1639 synth_opts->timeless_decoding = true;
1640 break;1640 break;
1641 case 'T':
1642 synth_opts->use_timestamp = true;
1643 break;
1641 case ' ':1644 case ' ':
1642 case ',':1645 case ',':
1643 break;1646 break;
tools/perf/util/auxtrace.h+3−0
@@ -99,6 +99,7 @@ enum itrace_period_type { · 98 unmodified lines
99 * @remote_access: whether to synthesize remote access events99 * @remote_access: whether to synthesize remote access events
100 * @mem: whether to synthesize memory events100 * @mem: whether to synthesize memory events
101 * @timeless_decoding: prefer "timeless" decoding i.e. ignore timestamps101 * @timeless_decoding: prefer "timeless" decoding i.e. ignore timestamps
102 * @use_timestamp: use the timestamp trace as kernel time
102 * @vm_time_correlation: perform VM Time Correlation103 * @vm_time_correlation: perform VM Time Correlation
103 * @vm_tm_corr_dry_run: VM Time Correlation dry-run104 * @vm_tm_corr_dry_run: VM Time Correlation dry-run
104 * @vm_tm_corr_args: VM Time Correlation implementation-specific arguments105 * @vm_tm_corr_args: VM Time Correlation implementation-specific arguments
@@ -146,6 +147,7 @@ struct itrace_synth_opts { · 41 unmodified lines
146 bool remote_access;147 bool remote_access;
147 bool mem;148 bool mem;
148 bool timeless_decoding;149 bool timeless_decoding;
150 bool use_timestamp;
149 bool vm_time_correlation;151 bool vm_time_correlation;
150 bool vm_tm_corr_dry_run;152 bool vm_tm_corr_dry_run;
151 char *vm_tm_corr_args;153 char *vm_tm_corr_args;
@@ -678,6 +680,7 @@ bool auxtrace__evsel_is_auxtrace(struct perf_session *session, · 526 unmodified lines
678" q: quicker (less detailed) decoding\n" \680" q: quicker (less detailed) decoding\n" \
679" A: approximate IPC\n" \681" A: approximate IPC\n" \
680" Z: prefer to ignore timestamps (so-called \"timeless\" decoding)\n" \682" Z: prefer to ignore timestamps (so-called \"timeless\" decoding)\n" \
683" T: use the timestamp trace as kernel time\n" \
681" PERIOD[ns|us|ms|i|t]: specify period to sample stream\n" \684" PERIOD[ns|us|ms|i|t]: specify period to sample stream\n" \
682" concatenate multiple options. Default is iybxwpe or cewp\n"685" concatenate multiple options. Default is iybxwpe or cewp\n"
683 686
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
129 al.sym = he->ms.sym;129 al.sym = he->ms.sym;
130 130
131 notes = symbol__annotation(he->ms.sym);131 notes = symbol__annotation(he->ms.sym);
132 if (!notes || !notes->src || !notes->src->cycles_hist)132 if (!notes || !notes->branch || !notes->branch->cycles_hist)
133 return 0;133 return 0;
134 ch = notes->src->cycles_hist;134 ch = notes->branch->cycles_hist;
135 for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {135 for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
136 if (ch[i].num_aggr) {136 if (ch[i].num_aggr) {
137 struct block_info *bi;137 struct block_info *bi;
@@ -464,8 +464,7 @@ void block_info__free_report(struct block_report *reps, int nr_reps) · 326 unmodified lines
464}464}
465 465
466int report__browse_block_hists(struct block_hist *bh, float min_percent,466int report__browse_block_hists(struct block_hist *bh, float min_percent,
467 struct evsel *evsel, struct perf_env *env,467 struct evsel *evsel, struct perf_env *env)
468 struct annotation_options *annotation_opts)
469{468{
470 int ret;469 int ret;
471 470
@@ -477,8 +476,7 @@ int report__browse_block_hists(struct block_hist *bh, float min_percent, · 5 unmodified lines
477 return 0;476 return 0;
478 case 1:477 case 1:
479 symbol_conf.report_individual_block = true;478 symbol_conf.report_individual_block = true;
480 ret = block_hists_tui_browse(bh, evsel, min_percent,479 ret = block_hists_tui_browse(bh, evsel, min_percent, env);
481 env, annotation_opts);
482 return ret;480 return ret;
483 default:481 default:
484 return -1;482 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
78void block_info__free_report(struct block_report *reps, int nr_reps);78void block_info__free_report(struct block_report *reps, int nr_reps);
79 79
80int report__browse_block_hists(struct block_hist *bh, float min_percent,80int report__browse_block_hists(struct block_hist *bh, float min_percent,
81 struct evsel *evsel, struct perf_env *env,81 struct evsel *evsel, struct perf_env *env);
82 struct annotation_options *annotation_opts);
83 82
84float block_info__total_cycles_percent(struct hist_entry *he);83float block_info__total_cycles_percent(struct hist_entry *he);
85 84
tools/perf/util/block-range.c+6−1
@@ -311,6 +311,7 @@ done: · 310 unmodified lines
311double block_range__coverage(struct block_range *br)311double block_range__coverage(struct block_range *br)
312{312{
313 struct symbol *sym;313 struct symbol *sym;
314 struct annotated_branch *branch;
314 315
315 if (!br) {316 if (!br) {
316 if (block_ranges.blocks)317 if (block_ranges.blocks)
@@ -323,5 +324,9 @@ double block_range__coverage(struct block_range *br) · 6 unmodified lines
323 if (!sym)324 if (!sym)
324 return -1;325 return -1;
325 326
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;
327}332}
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
386 int err;386 int err;
387 int fd;387 int fd;
388 388
389 if (opts->no_bpf_event)
390 return 0;
391
389 event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size);392 event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size);
390 if (!event)393 if (!event)
391 return -1;394 return -1;
@@ -542,9 +545,9 @@ int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env) · 150 unmodified lines
542 return evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);545 return evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
543}546}
544 547
545void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,548void __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
546 struct perf_env *env,549 struct perf_env *env,
547 FILE *fp)550 FILE *fp)
548{551{
549 __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens);552 __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens);
550 __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms);553 __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
560 if (info->btf_id) {563 if (info->btf_id) {
561 struct btf_node *node;564 struct btf_node *node;
562 565
563 node = perf_env__find_btf(env, info->btf_id);566 node = __perf_env__find_btf(env, info->btf_id);
564 if (node)567 if (node)
565 btf = btf__new((__u8 *)(node->data),568 btf = btf__new((__u8 *)(node->data),
566 node->data_size);569 node->data_size);
tools/perf/util/bpf-event.h+6−6
@@ -33,9 +33,9 @@ struct btf_node { · 32 unmodified lines
33int machine__process_bpf(struct machine *machine, union perf_event *event,33int machine__process_bpf(struct machine *machine, union perf_event *event,
34 struct perf_sample *sample);34 struct perf_sample *sample);
35int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env);35int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env);
36void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,36void __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
37 struct perf_env *env,37 struct perf_env *env,
38 FILE *fp);38 FILE *fp);
39#else39#else
40static inline int machine__process_bpf(struct machine *machine __maybe_unused,40static inline int machine__process_bpf(struct machine *machine __maybe_unused,
41 union perf_event *event __maybe_unused,41 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
50 return 0;50 return 0;
51}51}
52 52
53static inline void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info __maybe_unused,53static inline void __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info __maybe_unused,
54 struct perf_env *env __maybe_unused,54 struct perf_env *env __maybe_unused,
55 FILE *fp __maybe_unused)55 FILE *fp __maybe_unused)
56{56{
57 57
58}58}
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
455 return -1;455 return -1;
456 456
457 if (!all_cpu_map) {457 if (!all_cpu_map) {
458 all_cpu_map = perf_cpu_map__new(NULL);458 all_cpu_map = perf_cpu_map__new_online_cpus();
459 if (!all_cpu_map)459 if (!all_cpu_map)
460 return -1;460 return -1;
461 }461 }
tools/perf/util/bpf_lock_contention.c+1−1
@@ -318,7 +318,7 @@ int lock_contention_read(struct lock_contention *con) · 317 unmodified lines
318 }318 }
319 319
320 /* make sure it loads the kernel map */320 /* make sure it loads the kernel map */
321 map__load(maps__first(machine->kmaps)->map);321 maps__load_first(machine->kmaps);
322 322
323 prev_key = NULL;323 prev_key = NULL;
324 while (!bpf_map_get_next_key(fd, prev_key, &key)) {324 while (!bpf_map_get_next_key(fd, prev_key, &key)) {
tools/perf/util/compress.h+5−2
@@ -3,6 +3,8 @@ · 2 unmodified lines
3#define PERF_COMPRESS_H3#define PERF_COMPRESS_H
4 4
5#include <stdbool.h>5#include <stdbool.h>
6#include <stddef.h>
7#include <sys/types.h>
6#ifdef HAVE_ZSTD_SUPPORT8#ifdef HAVE_ZSTD_SUPPORT
7#include <zstd.h>9#include <zstd.h>
8#endif10#endif
@@ -21,6 +23,7 @@ struct zstd_data { · 12 unmodified lines
21#ifdef HAVE_ZSTD_SUPPORT23#ifdef HAVE_ZSTD_SUPPORT
22 ZSTD_CStream *cstream;24 ZSTD_CStream *cstream;
23 ZSTD_DStream *dstream;25 ZSTD_DStream *dstream;
26 int comp_level;
24#endif27#endif
25};28};
26 29
@@ -29,7 +32,7 @@ struct zstd_data { · 2 unmodified lines
29int zstd_init(struct zstd_data *data, int level);32int zstd_init(struct zstd_data *data, int level);
30int zstd_fini(struct zstd_data *data);33int zstd_fini(struct zstd_data *data);
31 34
32size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,35ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,
33 void *src, size_t src_size, size_t max_record_size,36 void *src, size_t src_size, size_t max_record_size,
34 size_t process_header(void *record, size_t increment));37 size_t process_header(void *record, size_t increment));
35 38
@@ -48,7 +51,7 @@ static inline int zstd_fini(struct zstd_data *data __maybe_unused) · 12 unmodified lines
48}51}
49 52
50static inline53static inline
51size_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused,54ssize_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused,
52 void *dst __maybe_unused, size_t dst_size __maybe_unused,55 void *dst __maybe_unused, size_t dst_size __maybe_unused,
53 void *src __maybe_unused, size_t src_size __maybe_unused,56 void *src __maybe_unused, size_t src_size __maybe_unused,
54 size_t max_record_size __maybe_unused,57 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
672 static struct perf_cpu_map *online;672 static struct perf_cpu_map *online;
673 673
674 if (!online)674 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 */
676 676
677 return online;677 return online;
678}678}
tools/perf/util/cputopo.c+1−1
@@ -267,7 +267,7 @@ struct cpu_topology *cpu_topology__new(void) · 266 unmodified lines
267 ncpus = cpu__max_present_cpu().cpu;267 ncpus = cpu__max_present_cpu().cpu;
268 268
269 /* build online CPU map */269 /* build online CPU map */
270 map = perf_cpu_map__new(NULL);270 map = perf_cpu_map__new_online_cpus();
271 if (map == NULL) {271 if (map == NULL) {
272 pr_debug("failed to get system cpumap\n");272 pr_debug("failed to get system cpumap\n");
273 return NULL;273 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
3346 etm->metadata = metadata;3346 etm->metadata = metadata;
3347 etm->auxtrace_type = auxtrace_info->type;3347 etm->auxtrace_type = auxtrace_info->type;
3348 3348
3349 /* Use virtual timestamps if all ETMs report ts_source = 1 */3349 if (etm->synth_opts.use_timestamp)
3350 etm->has_virtual_ts = cs_etm__has_virtual_ts(metadata, num_cpu);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);
3351 3363
3352 if (!etm->has_virtual_ts)3364 if (!etm->has_virtual_ts)
3353 ui__warning("Virtual timestamps are not enabled, or not supported by the traced system.\n"3365 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");
3355 3370
3356 etm->auxtrace.process_event = cs_etm__process_event;3371 etm->auxtrace.process_event = cs_etm__process_event;
3357 etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;3372 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
253 */253 */
254 addr_location__init(&al);254 addr_location__init(&al);
255 al.sym = node->ms.sym;255 al.sym = node->ms.sym;
256 al.map = node->ms.map;256 al.map = map__get(node->ms.map);
257 al.maps = thread__maps(thread);257 al.maps = maps__get(thread__maps(thread));
258 al.addr = node->ip;258 al.addr = node->ip;
259 259
260 if (al.map && !al.sym)260 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
38int debug_ordered_events;38int debug_ordered_events;
39static int redirect_to_stderr;39static int redirect_to_stderr;
40int debug_data_convert;40int debug_data_convert;
41static FILE *debug_file;41static FILE *_debug_file;
42bool debug_display_time;42bool debug_display_time;
43 43
44FILE *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
44void debug_set_file(FILE *file)53void debug_set_file(FILE *file)
45{54{
46 debug_file = file;55 _debug_file = file;
47}56}
48 57
49void debug_set_display_time(bool set)58void 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
78 if (use_browser >= 1 && !redirect_to_stderr) {87 if (use_browser >= 1 && !redirect_to_stderr) {
79 ui_helpline__vshow(fmt, args);88 ui_helpline__vshow(fmt, args);
80 } else {89 } else {
81 ret = fprintf_time(debug_file);90 ret = fprintf_time(debug_file());
82 ret += vfprintf(debug_file, fmt, args);91 ret += vfprintf(debug_file(), fmt, args);
83 }92 }
84 }93 }
85 94
@@ -107,9 +116,8 @@ static int veprintf_time(u64 t, const char *fmt, va_list args) · 21 unmodified lines
107 nsecs -= secs * NSEC_PER_SEC;116 nsecs -= secs * NSEC_PER_SEC;
108 usecs = nsecs / NSEC_PER_USEC;117 usecs = nsecs / NSEC_PER_USEC;
109 118
110 ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",119 ret = fprintf(debug_file(), "[%13" PRIu64 ".%06" PRIu64 "] ", secs, usecs);
111 secs, usecs);120 ret += vfprintf(debug_file(), fmt, args);
112 ret += vfprintf(stderr, fmt, args);
113 return ret;121 return ret;
114}122}
115 123
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
77int veprintf(int level, int var, const char *fmt, va_list args);77int veprintf(int level, int var, const char *fmt, va_list args);
78 78
79int perf_debug_option(const char *str);79int perf_debug_option(const char *str);
80FILE *debug_file(void);
80void debug_set_file(FILE *file);81void debug_set_file(FILE *file);
81void debug_set_display_time(bool set);82void debug_set_display_time(bool set);
82void perf_debug_setup(void);83void 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 */
27static char *debuginfo_path; /* Currently dummy */
28
29static 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 */
40static 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;
68error:
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
78static 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
91enum 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
100struct 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
127out:
128 /* if failed to open all distro debuginfo, open given binary */
129 return dinfo ? : __debuginfo__new(path);
130}
131
132void 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 */
142int 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
180int 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 */
13struct 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 */
22struct debuginfo *debuginfo__new(const char *path);
23void debuginfo__delete(struct debuginfo *dbg);
24
25int 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 */
31struct debuginfo {
32};
33
34static inline struct debuginfo *debuginfo__new(const char *path __maybe_unused)
35{
36 return NULL;
37}
38
39static inline void debuginfo__delete(struct debuginfo *dbg __maybe_unused)
40{
41}
42
43static 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
53int get_source_from_debuginfod(const char *raw_path, const char *sbuild_id,
54 char **new_path);
55#else /* HAVE_DEBUGINFOD_SUPPORT */
56static 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
31#include "debug.h"31#include "debug.h"
32#include "string2.h"32#include "string2.h"
33#include "vdso.h"33#include "vdso.h"
34#include "annotate-data.h"
34 35
35static const char * const debuglink_paths[] = {36static const char * const debuglink_paths[] = {
36 "%.0s%s",37 "%.0s%s",
@@ -1327,6 +1328,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id) · 1290 unmodified lines
1327 dso->data.cache = RB_ROOT;1328 dso->data.cache = RB_ROOT;
1328 dso->inlined_nodes = RB_ROOT_CACHED;1329 dso->inlined_nodes = RB_ROOT_CACHED;
1329 dso->srclines = RB_ROOT_CACHED;1330 dso->srclines = RB_ROOT_CACHED;
1331 dso->data_types = RB_ROOT;
1330 dso->data.fd = -1;1332 dso->data.fd = -1;
1331 dso->data.status = DSO_DATA_STATUS_UNKNOWN;1333 dso->data.status = DSO_DATA_STATUS_UNKNOWN;
1332 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;1334 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
@@ -1370,6 +1372,8 @@ void dso__delete(struct dso *dso) · 37 unmodified lines
1370 symbols__delete(&dso->symbols);1372 symbols__delete(&dso->symbols);
1371 dso->symbol_names_len = 0;1373 dso->symbol_names_len = 0;
1372 zfree(&dso->symbol_names);1374 zfree(&dso->symbol_names);
1375 annotated_data_type__tree_delete(&dso->data_types);
1376
1373 if (dso->short_name_allocated) {1377 if (dso->short_name_allocated) {
1374 zfree((char **)&dso->short_name);1378 zfree((char **)&dso->short_name);
1375 dso->short_name_allocated = false;1379 dso->short_name_allocated = false;
tools/perf/util/dso.h+2−0
@@ -154,6 +154,8 @@ struct dso { · 153 unmodified lines
154 size_t symbol_names_len;154 size_t symbol_names_len;
155 struct rb_root_cached inlined_nodes;155 struct rb_root_cached inlined_nodes;
156 struct rb_root_cached srclines;156 struct rb_root_cached srclines;
157 struct rb_root data_types;
158
157 struct {159 struct {
158 u64 addr;160 u64 addr;
159 struct symbol *symbol;161 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
1051}1051}
1052 1052
1053/**1053/**
1054 * die_get_typename - Get the name of given variable DIE1054 * die_get_typename_from_type - Get the name of given type DIE
1055 * @vr_die: a variable DIE1055 * @type_die: a type DIE
1056 * @buf: a strbuf for result type name1056 * @buf: a strbuf for result type name
1057 *1057 *
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.
1059 * and Return -ENOENT if failed to find type name.1059 * and Return -ENOENT if failed to find type name.
1060 * Note that the result will stores typedef name if possible, and stores1060 * Note that the result will stores typedef name if possible, and stores
1061 * "*(function_type)" if the type is a function pointer.1061 * "*(function_type)" if the type is a function pointer.
1062 */1062 */
1063int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)1063int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf)
1064{1064{
1065 Dwarf_Die type;
1066 int tag, ret;1065 int tag, ret;
1067 const char *tmp = "";1066 const char *tmp = "";
1068 1067
1069 if (__die_get_real_type(vr_die, &type) == NULL)1068 tag = dwarf_tag(type_die);
1070 return -ENOENT;
1071
1072 tag = dwarf_tag(&type);
1073 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)1069 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
1074 tmp = "*";1070 tmp = "*";
1075 else if (tag == DW_TAG_subroutine_type) {1071 else if (tag == DW_TAG_subroutine_type) {
1076 /* Function pointer */1072 /* Function pointer */
1077 return strbuf_add(buf, "(function_type)", 15);1073 return strbuf_add(buf, "(function_type)", 15);
1078 } else {1074 } else {
1079 const char *name = dwarf_diename(&type);1075 const char *name = dwarf_diename(type_die);
1080 1076
1081 if (tag == DW_TAG_union_type)1077 if (tag == DW_TAG_union_type)
1082 tmp = "union ";1078 tmp = "union ";
@@ -1089,8 +1085,35 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) · 6 unmodified lines
1089 /* Write a base name */1085 /* Write a base name */
1090 return strbuf_addf(buf, "%s%s", tmp, name ?: "");1086 return strbuf_addf(buf, "%s%s", tmp, name ?: "");
1091 }1087 }
1092 ret = die_get_typename(&type, buf);1088 ret = die_get_typename(type_die, buf);
1093 return ret ? ret : strbuf_addstr(buf, tmp);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 */
1109int 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);
1094}1117}
1095 1118
1096/**1119/**
@@ -1238,12 +1261,151 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) · 141 unmodified lines
1238out:1261out:
1239 return ret;1262 return ret;
1240}1263}
1241#else1264
1242int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,1265/* Interval parameters for __die_find_var_reg_cb() */
1243 Dwarf_Die *vr_die __maybe_unused,1266struct find_var_data {
1244 struct strbuf *buf __maybe_unused)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. */
1281static 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 */
1326Dwarf_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 */
1337static 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 */
1395Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc,
1396 Dwarf_Addr addr, Dwarf_Die *die_mem,
1397 int *offset)
1245{1398{
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;
1247}1409}
1248#endif1410#endif
1249 1411
@@ -1425,3 +1587,56 @@ void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, · 175 unmodified lines
1425 1587
1426 *entrypc = postprologue_addr;1588 *entrypc = postprologue_addr;
1427}1589}
1590
1591/* Internal parameters for __die_find_scope_cb() */
1592struct 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
1601static 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 */
1631int 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
116Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,116Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
117 Dwarf_Die *die_mem);117 Dwarf_Die *die_mem);
118 118
119/* Get the name of given type DIE */
120int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf);
121
119/* Get the name of given variable DIE */122/* Get the name of given variable DIE */
120int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);123int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
121 124
122/* Get the name and type of given variable DIE, stored as "type\tname" */125/* Get the name and type of given variable DIE, stored as "type\tname" */
123int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);126int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
124int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
125 127
126/* Check if target program is compiled with optimization */128/* Check if target program is compiled with optimization */
127bool die_is_optimized_target(Dwarf_Die *cu_die);129bool die_is_optimized_target(Dwarf_Die *cu_die);
@@ -130,4 +132,49 @@ bool die_is_optimized_target(Dwarf_Die *cu_die); · 2 unmodified lines
130void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,132void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
131 Dwarf_Addr *entrypc);133 Dwarf_Addr *entrypc);
132 134
133#endif135/* Get the list of including scopes */
136int 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 */
141int 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 */
144Dwarf_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' */
148Dwarf_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
154static 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
161static 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
169static 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
5 * Written by: Masami Hiramatsu <mhiramat@kernel.org>5 * Written by: Masami Hiramatsu <mhiramat@kernel.org>
6 */6 */
7 7
8#include <stdlib.h>
9#include <string.h>
8#include <debug.h>10#include <debug.h>
9#include <dwarf-regs.h>11#include <dwarf-regs.h>
10#include <elf.h>12#include <elf.h>
13#include <errno.h>
11#include <linux/kernel.h>14#include <linux/kernel.h>
12 15
13#ifndef EM_AARCH6416#ifndef EM_AARCH64
@@ -68,3 +71,34 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) · 54 unmodified lines
68 }71 }
69 return NULL;72 return NULL;
70}73}
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 */
81int 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
3#include "debug.h"3#include "debug.h"
4#include "env.h"4#include "env.h"
5#include "util/header.h"5#include "util/header.h"
6#include "linux/compiler.h"
6#include <linux/ctype.h>7#include <linux/ctype.h>
7#include <linux/zalloc.h>8#include <linux/zalloc.h>
8#include "cgroup.h"9#include "cgroup.h"
@@ -12,6 +13,7 @@ · 3 unmodified lines
12#include <string.h>13#include <string.h>
13#include "pmus.h"14#include "pmus.h"
14#include "strbuf.h"15#include "strbuf.h"
16#include "trace/beauty/beauty.h"
15 17
16struct perf_env perf_env;18struct perf_env perf_env;
17 19
@@ -22,13 +24,19 @@ struct perf_env perf_env; · 4 unmodified lines
22 24
23void perf_env__insert_bpf_prog_info(struct perf_env *env,25void perf_env__insert_bpf_prog_info(struct perf_env *env,
24 struct bpf_prog_info_node *info_node)26 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
33void __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node)
25{34{
26 __u32 prog_id = info_node->info_linear->info.id;35 __u32 prog_id = info_node->info_linear->info.id;
27 struct bpf_prog_info_node *node;36 struct bpf_prog_info_node *node;
28 struct rb_node *parent = NULL;37 struct rb_node *parent = NULL;
29 struct rb_node **p;38 struct rb_node **p;
30 39
31 down_write(&env->bpf_progs.lock);
32 p = &env->bpf_progs.infos.rb_node;40 p = &env->bpf_progs.infos.rb_node;
33 41
34 while (*p != NULL) {42 while (*p != NULL) {
@@ -40,15 +48,13 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env, · 5 unmodified lines
40 p = &(*p)->rb_right;48 p = &(*p)->rb_right;
41 } else {49 } else {
42 pr_debug("duplicated bpf prog info %u\n", prog_id);50 pr_debug("duplicated bpf prog info %u\n", prog_id);
43 goto out;51 return;
44 }52 }
45 }53 }
46 54
47 rb_link_node(&info_node->rb_node, parent, p);55 rb_link_node(&info_node->rb_node, parent, p);
48 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);56 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
49 env->bpf_progs.infos_cnt++;57 env->bpf_progs.infos_cnt++;
50out:
51 up_write(&env->bpf_progs.lock);
52}58}
53 59
54struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,60struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
@@ -77,14 +83,22 @@ out: · 22 unmodified lines
77}83}
78 84
79bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)85bool 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
95bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
80{96{
81 struct rb_node *parent = NULL;97 struct rb_node *parent = NULL;
82 __u32 btf_id = btf_node->id;98 __u32 btf_id = btf_node->id;
83 struct btf_node *node;99 struct btf_node *node;
84 struct rb_node **p;100 struct rb_node **p;
85 bool ret = true;
86 101
87 down_write(&env->bpf_progs.lock);
88 p = &env->bpf_progs.btfs.rb_node;102 p = &env->bpf_progs.btfs.rb_node;
89 103
90 while (*p != NULL) {104 while (*p != NULL) {
@@ -96,25 +110,31 @@ bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) · 5 unmodified lines
96 p = &(*p)->rb_right;110 p = &(*p)->rb_right;
97 } else {111 } else {
98 pr_debug("duplicated btf %u\n", btf_id);112 pr_debug("duplicated btf %u\n", btf_id);
99 ret = false;113 return false;
100 goto out;
101 }114 }
102 }115 }
103 116
104 rb_link_node(&btf_node->rb_node, parent, p);117 rb_link_node(&btf_node->rb_node, parent, p);
105 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);118 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
106 env->bpf_progs.btfs_cnt++;119 env->bpf_progs.btfs_cnt++;
107out:120 return true;
108 up_write(&env->bpf_progs.lock);
109 return ret;
110}121}
111 122
112struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)123struct 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
133struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id)
113{134{
114 struct btf_node *node = NULL;135 struct btf_node *node = NULL;
115 struct rb_node *n;136 struct rb_node *n;
116 137
117 down_read(&env->bpf_progs.lock);
118 n = env->bpf_progs.btfs.rb_node;138 n = env->bpf_progs.btfs.rb_node;
119 139
120 while (n) {140 while (n) {
@@ -124,13 +144,9 @@ struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) · 3 unmodified lines
124 else if (btf_id > node->id)144 else if (btf_id > node->id)
125 n = n->rb_right;145 n = n->rb_right;
126 else146 else
127 goto out;147 return node;
128 }148 }
129 node = NULL;149 return NULL;
130
131out:
132 up_read(&env->bpf_progs.lock);
133 return node;
134}150}
135 151
136/* purge data in bpf_progs.infos tree */152/* purge data in bpf_progs.infos tree */
@@ -453,6 +469,18 @@ const char *perf_env__arch(struct perf_env *env) · 316 unmodified lines
453 return normalize_arch(arch_name);469 return normalize_arch(arch_name);
454}470}
455 471
472const 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
456const char *perf_env__cpuid(struct perf_env *env)484const char *perf_env__cpuid(struct perf_env *env)
457{485{
458 int status;486 int status;
@@ -531,6 +559,24 @@ int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu) · 72 unmodified lines
531 return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;559 return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;
532}560}
533 561
562bool 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 }
576out_error:
577 return false;
578}
579
534char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,580char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
535 const char *cap)581 const char *cap)
536{582{
tools/perf/util/env.h+17−0
@@ -46,10 +46,17 @@ struct hybrid_node { · 45 unmodified lines
46struct pmu_caps {46struct pmu_caps {
47 int nr_caps;47 int nr_caps;
48 unsigned int max_branches;48 unsigned int max_branches;
49 unsigned int br_cntr_nr;
50 unsigned int br_cntr_width;
51
49 char **caps;52 char **caps;
50 char *pmu_name;53 char *pmu_name;
51};54};
52 55
56typedef const char *(arch_syscalls__strerrno_t)(int err);
57
58arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch);
59
53struct perf_env {60struct perf_env {
54 char *hostname;61 char *hostname;
55 char *os_release;62 char *os_release;
@@ -62,6 +69,8 @@ struct perf_env { · 6 unmodified lines
62 unsigned long long total_mem;69 unsigned long long total_mem;
63 unsigned int msr_pmu_type;70 unsigned int msr_pmu_type;
64 unsigned int max_branches;71 unsigned int max_branches;
72 unsigned int br_cntr_nr;
73 unsigned int br_cntr_width;
65 int kernel_is_64_bit;74 int kernel_is_64_bit;
66 75
67 int nr_cmdline;76 int nr_cmdline;
@@ -130,6 +139,7 @@ struct perf_env { · 62 unmodified lines
130 */139 */
131 bool enabled;140 bool enabled;
132 } clock;141 } clock;
142 arch_syscalls__strerrno_t *arch_strerrno;
133};143};
134 144
135enum perf_compress_type {145enum perf_compress_type {
@@ -159,19 +169,26 @@ int perf_env__read_cpu_topology_map(struct perf_env *env); · 23 unmodified lines
159void cpu_cache_level__free(struct cpu_cache_level *cache);169void cpu_cache_level__free(struct cpu_cache_level *cache);
160 170
161const char *perf_env__arch(struct perf_env *env);171const char *perf_env__arch(struct perf_env *env);
172const char *perf_env__arch_strerrno(struct perf_env *env, int err);
162const char *perf_env__cpuid(struct perf_env *env);173const char *perf_env__cpuid(struct perf_env *env);
163const char *perf_env__raw_arch(struct perf_env *env);174const char *perf_env__raw_arch(struct perf_env *env);
164int perf_env__nr_cpus_avail(struct perf_env *env);175int perf_env__nr_cpus_avail(struct perf_env *env);
165 176
166void perf_env__init(struct perf_env *env);177void perf_env__init(struct perf_env *env);
178void __perf_env__insert_bpf_prog_info(struct perf_env *env,
179 struct bpf_prog_info_node *info_node);
167void perf_env__insert_bpf_prog_info(struct perf_env *env,180void perf_env__insert_bpf_prog_info(struct perf_env *env,
168 struct bpf_prog_info_node *info_node);181 struct bpf_prog_info_node *info_node);
169struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,182struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
170 __u32 prog_id);183 __u32 prog_id);
171bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);184bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
185bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
172struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);186struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
187struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id);
173 188
174int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu);189int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu);
175char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,190char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
176 const char *cap);191 const char *cap);
192
193bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name);
177#endif /* __PERF_ENV_H */194#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
617 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {617 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
618 al->level = 'k';618 al->level = 'k';
619 maps = machine__kernel_maps(machine);619 maps = machine__kernel_maps(machine);
620 load_map = true;620 load_map = !symbol_conf.lazy_load_kernel_maps;
621 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {621 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
622 al->level = '.';622 al->level = '.';
623 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {623 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
624 al->level = 'g';624 al->level = 'g';
625 maps = machine__kernel_maps(machine);625 maps = machine__kernel_maps(machine);
626 load_map = true;626 load_map = !symbol_conf.lazy_load_kernel_maps;
627 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {627 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
628 al->level = 'u';628 al->level = 'u';
629 } else {629 } 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
1056 return -1;1056 return -1;
1057 1057
1058 if (target__uses_dummy_map(target))1058 if (target__uses_dummy_map(target))
1059 cpus = perf_cpu_map__dummy_new();1059 cpus = perf_cpu_map__new_any_cpu();
1060 else1060 else
1061 cpus = perf_cpu_map__new(target->cpu_list);1061 cpus = perf_cpu_map__new(target->cpu_list);
1062 1062
@@ -1352,7 +1352,7 @@ static int evlist__create_syswide_maps(struct evlist *evlist) · 289 unmodified lines
1352 * error, and we may not want to do that fallback to a1352 * error, and we may not want to do that fallback to a
1353 * default cpu identity map :-\1353 * default cpu identity map :-\
1354 */1354 */
1355 cpus = perf_cpu_map__new(NULL);1355 cpus = perf_cpu_map__new_online_cpus();
1356 if (!cpus)1356 if (!cpus)
1357 goto out;1357 goto out;
1358 1358
@@ -2518,3 +2518,33 @@ void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_lis · 1159 unmodified lines
2518 }2518 }
2519 perf_cpu_map__put(user_requested_cpus);2519 perf_cpu_map__put(user_requested_cpus);
2520}2520}
2521
2522void 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
442int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);442int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);
443void evlist__check_mem_load_aux(struct evlist *evlist);443void evlist__check_mem_load_aux(struct evlist *evlist);
444void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);444void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);
445void evlist__uniquify_name(struct evlist *evlist);
445 446
446#endif /* __PERF_EVLIST_H */447#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
1801 1801
1802 if (cpus == NULL) {1802 if (cpus == NULL) {
1803 if (empty_cpu_map == NULL) {1803 if (empty_cpu_map == NULL) {
1804 empty_cpu_map = perf_cpu_map__dummy_new();1804 empty_cpu_map = perf_cpu_map__new_any_cpu();
1805 if (empty_cpu_map == NULL)1805 if (empty_cpu_map == NULL)
1806 return -ENOMEM;1806 return -ENOMEM;
1807 }1807 }
@@ -1832,6 +1832,8 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, · 24 unmodified lines
1832 1832
1833static void evsel__disable_missing_features(struct evsel *evsel)1833static void evsel__disable_missing_features(struct evsel *evsel)
1834{1834{
1835 if (perf_missing_features.branch_counters)
1836 evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_COUNTERS;
1835 if (perf_missing_features.read_lost)1837 if (perf_missing_features.read_lost)
1836 evsel->core.attr.read_format &= ~PERF_FORMAT_LOST;1838 evsel->core.attr.read_format &= ~PERF_FORMAT_LOST;
1837 if (perf_missing_features.weight_struct) {1839 if (perf_missing_features.weight_struct) {
@@ -1885,7 +1887,12 @@ bool evsel__detect_missing_features(struct evsel *evsel) · 47 unmodified lines
1885 * Must probe features in the order they were added to the1887 * Must probe features in the order they were added to the
1886 * perf_event_attr interface.1888 * perf_event_attr interface.
1887 */1889 */
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 &&
1889 (evsel->core.attr.read_format & PERF_FORMAT_LOST)) {1896 (evsel->core.attr.read_format & PERF_FORMAT_LOST)) {
1890 perf_missing_features.read_lost = true;1897 perf_missing_features.read_lost = true;
1891 pr_debug2("switching off PERF_FORMAT_LOST support\n");1898 pr_debug2("switching off PERF_FORMAT_LOST support\n");
@@ -2318,6 +2325,22 @@ u64 evsel__bitfield_swap_branch_flags(u64 value) · 426 unmodified lines
2318 return new_val;2325 return new_val;
2319}2326}
2320 2327
2328static 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
2321int evsel__parse_sample(struct evsel *evsel, union perf_event *event,2344int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
2322 struct perf_sample *data)2345 struct perf_sample *data)
2323{2346{
@@ -2551,6 +2574,16 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event, · 227 unmodified lines
2551 2574
2552 OVERFLOW_CHECK(array, sz, max_size);2575 OVERFLOW_CHECK(array, sz, max_size);
2553 array = (void *)array + sz;2576 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 }
2554 }2587 }
2555 2588
2556 if (type & PERF_SAMPLE_REGS_USER) {2589 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
2820 2853
2821#endif2854#endif
2822 2855
2823bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize)2856bool evsel__fallback(struct evsel *evsel, struct target *target, int err,
2857 char *msg, size_t msgsize)
2824{2858{
2825 int paranoid;2859 int paranoid;
2826 2860
@@ -2828,18 +2862,19 @@ bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize) · 1 unmodified line
2828 evsel->core.attr.type == PERF_TYPE_HARDWARE &&2862 evsel->core.attr.type == PERF_TYPE_HARDWARE &&
2829 evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES) {2863 evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES) {
2830 /*2864 /*
2831 * If it's cycles then fall back to hrtimer based2865 * If it's cycles then fall back to hrtimer based cpu-clock sw
2832 * cpu-clock-tick sw counter, which is always available even if2866 * counter, which is always available even if no PMU support.
2833 * no PMU support.
2834 *2867 *
2835 * PPC returns ENXIO until 2.6.37 (behavior changed with commit2868 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
2836 * b0a873e).2869 * b0a873e).
2837 */2870 */
2838 scnprintf(msg, msgsize, "%s",
2839"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
2840
2841 evsel->core.attr.type = PERF_TYPE_SOFTWARE;2871 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");
2843 2878
2844 zfree(&evsel->name);2879 zfree(&evsel->name);
2845 return true;2880 return true;
tools/perf/util/evsel.h+3−1
@@ -191,6 +191,7 @@ struct perf_missing_features { · 190 unmodified lines
191 bool code_page_size;191 bool code_page_size;
192 bool weight_struct;192 bool weight_struct;
193 bool read_lost;193 bool read_lost;
194 bool branch_counters;
194};195};
195 196
196extern struct perf_missing_features perf_missing_features;197extern struct perf_missing_features perf_missing_features;
@@ -459,7 +460,8 @@ static inline bool evsel__is_clock(const struct evsel *evsel) · 262 unmodified lines
459 evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK);460 evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK);
460}461}
461 462
462bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize);463bool evsel__fallback(struct evsel *evsel, struct target *target, int err,
464 char *msg, size_t msgsize);
463int evsel__open_strerror(struct evsel *evsel, struct target *target,465int evsel__open_strerror(struct evsel *evsel, struct target *target,
464 int err, char *msg, size_t size);466 int err, char *msg, size_t size);
465 467
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
293 */293 */
294 phdr = elf_newphdr(e, 1);294 phdr = elf_newphdr(e, 1);
295 phdr[0].p_type = PT_LOAD;295 phdr[0].p_type = PT_LOAD;
296 phdr[0].p_offset = 0;296 phdr[0].p_offset = GEN_ELF_TEXT_OFFSET;
297 phdr[0].p_vaddr = 0;297 phdr[0].p_vaddr = GEN_ELF_TEXT_OFFSET;
298 phdr[0].p_paddr = 0;298 phdr[0].p_paddr = GEN_ELF_TEXT_OFFSET;
299 phdr[0].p_filesz = csize;299 phdr[0].p_filesz = csize;
300 phdr[0].p_memsz = csize;300 phdr[0].p_memsz = csize;
301 phdr[0].p_flags = PF_X | PF_R;301 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
1444 nodes = new_nodes;1444 nodes = new_nodes;
1445 size += 4;1445 size += 4;
1446 }1446 }
1447 ret = memory_node__read(&nodes[cnt++], idx);1447 ret = memory_node__read(&nodes[cnt], idx);
1448 if (!ret)
1449 cnt += 1;
1448 }1450 }
1449out:1451out:
1450 closedir(dir);1452 closedir(dir);
@@ -1847,8 +1849,8 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp) · 396 unmodified lines
1847 node = rb_entry(next, struct bpf_prog_info_node, rb_node);1849 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
1848 next = rb_next(&node->rb_node);1850 next = rb_next(&node->rb_node);
1849 1851
1850 bpf_event__print_bpf_prog_info(&node->info_linear->info,1852 __bpf_event__print_bpf_prog_info(&node->info_linear->info,
1851 env, fp);1853 env, fp);
1852 }1854 }
1853 1855
1854 up_read(&env->bpf_progs.lock);1856 up_read(&env->bpf_progs.lock);
@@ -2145,6 +2147,14 @@ static void print_pmu_caps(struct feat_fd *ff, FILE *fp) · 290 unmodified lines
2145 __print_pmu_caps(fp, pmu_caps->nr_caps, pmu_caps->caps,2147 __print_pmu_caps(fp, pmu_caps->nr_caps, pmu_caps->caps,
2146 pmu_caps->pmu_name);2148 pmu_caps->pmu_name);
2147 }2149 }
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 }
2148}2158}
2149 2159
2150static void print_pmu_mappings(struct feat_fd *ff, FILE *fp)2160static 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
3178 /* after reading from file, translate offset to address */3188 /* after reading from file, translate offset to address */
3179 bpil_offs_to_addr(info_linear);3189 bpil_offs_to_addr(info_linear);
3180 info_node->info_linear = info_linear;3190 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);
3182 }3192 }
3183 3193
3184 up_write(&env->bpf_progs.lock);3194 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
3225 if (__do_read(ff, node->data, data_size))3235 if (__do_read(ff, node->data, data_size))
3226 goto out;3236 goto out;
3227 3237
3228 perf_env__insert_btf(env, node);3238 __perf_env__insert_btf(env, node);
3229 node = NULL;3239 node = NULL;
3230 }3240 }
3231 3241
@@ -3259,7 +3269,9 @@ static int process_compressed(struct feat_fd *ff, · 27 unmodified lines
3259}3269}
3260 3270
3261static int __process_pmu_caps(struct feat_fd *ff, int *nr_caps,3271static 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)
3263{3275{
3264 char *name, *value, *ptr;3276 char *name, *value, *ptr;
3265 u32 nr_pmu_caps, i;3277 u32 nr_pmu_caps, i;
@@ -3294,6 +3306,12 @@ static int __process_pmu_caps(struct feat_fd *ff, int *nr_caps, · 28 unmodified lines
3294 if (!strcmp(name, "branches"))3306 if (!strcmp(name, "branches"))
3295 *max_branches = atoi(value);3307 *max_branches = atoi(value);
3296 3308
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
3297 free(value);3315 free(value);
3298 free(name);3316 free(name);
3299 }3317 }
@@ -3318,7 +3336,9 @@ static int process_cpu_pmu_caps(struct feat_fd *ff, · 18 unmodified lines
3318{3336{
3319 int ret = __process_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,3337 int ret = __process_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,
3320 &ff->ph->env.cpu_pmu_caps,3338 &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);
3322 3342
3323 if (!ret && !ff->ph->env.cpu_pmu_caps)3343 if (!ret && !ff->ph->env.cpu_pmu_caps)
3324 pr_debug("cpu pmu capabilities not available\n");3344 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
3347 for (i = 0; i < nr_pmu; i++) {3367 for (i = 0; i < nr_pmu; i++) {
3348 ret = __process_pmu_caps(ff, &pmu_caps[i].nr_caps,3368 ret = __process_pmu_caps(ff, &pmu_caps[i].nr_caps,
3349 &pmu_caps[i].caps,3369 &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);
3351 if (ret)3373 if (ret)
3352 goto err;3374 goto err;
3353 3375
@@ -4369,9 +4391,10 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) · 1015 unmodified lines
4369 ret += fprintf(fp, "... ");4391 ret += fprintf(fp, "... ");
4370 4392
4371 map = cpu_map__new_data(&ev->cpus.cpus);4393 map = cpu_map__new_data(&ev->cpus.cpus);
4372 if (map)4394 if (map) {
4373 ret += cpu_map__fprintf(map, fp);4395 ret += cpu_map__fprintf(map, fp);
4374 else4396 perf_cpu_map__put(map);
4397 } else
4375 ret += fprintf(fp, "failed to get cpus\n");4398 ret += fprintf(fp, "failed to get cpus\n");
4376 break;4399 break;
4377 default:4400 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
123 if (dump_trace)123 if (dump_trace)
124 hisi_ptt_dump_event(ptt, data, size);124 hisi_ptt_dump_event(ptt, data, size);
125 125
126 free(data);
126 return 0;127 return 0;
127}128}
128 129
tools/perf/util/hist.h+11−17
@@ -82,6 +82,9 @@ enum hist_column { · 81 unmodified lines
82 HISTC_ADDR_TO,82 HISTC_ADDR_TO,
83 HISTC_ADDR,83 HISTC_ADDR,
84 HISTC_SIMD,84 HISTC_SIMD,
85 HISTC_TYPE,
86 HISTC_TYPE_OFFSET,
87 HISTC_SYMBOL_OFFSET,
85 HISTC_NR_COLS, /* Last entry */88 HISTC_NR_COLS, /* Last entry */
86};89};
87 90
@@ -457,7 +460,6 @@ struct hist_browser_timer { · 369 unmodified lines
457 int refresh;460 int refresh;
458};461};
459 462
460struct annotation_options;
461struct res_sample;463struct res_sample;
462 464
463enum rstype {465enum rstype {
@@ -473,16 +475,13 @@ struct block_hist; · 9 unmodified lines
473void attr_to_script(char *buf, struct perf_event_attr *attr);475void attr_to_script(char *buf, struct perf_event_attr *attr);
474 476
475int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,477int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
476 struct hist_browser_timer *hbt,478 struct hist_browser_timer *hbt);
477 struct annotation_options *annotation_opts);
478 479
479int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,480int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
480 struct hist_browser_timer *hbt,481 struct hist_browser_timer *hbt);
481 struct annotation_options *annotation_opts);
482 482
483int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,483int 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,484 float min_pcnt, struct perf_env *env, bool warn_lost_event);
485 struct annotation_options *annotation_options);
486 485
487int script_browse(const char *script_opt, struct evsel *evsel);486int script_browse(const char *script_opt, struct evsel *evsel);
488 487
@@ -492,8 +491,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res, · 3 unmodified lines
492void res_sample_init(void);491void res_sample_init(void);
493 492
494int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,493int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
495 float min_percent, struct perf_env *env,494 float min_percent, struct perf_env *env);
496 struct annotation_options *annotation_opts);
497#else495#else
498static inline496static inline
499int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused,497int 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
501 struct hist_browser_timer *hbt __maybe_unused,499 struct hist_browser_timer *hbt __maybe_unused,
502 float min_pcnt __maybe_unused,500 float min_pcnt __maybe_unused,
503 struct perf_env *env __maybe_unused,501 struct perf_env *env __maybe_unused,
504 bool warn_lost_event __maybe_unused,502 bool warn_lost_event __maybe_unused)
505 struct annotation_options *annotation_options __maybe_unused)
506{503{
507 return 0;504 return 0;
508}505}
509static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused,506static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
510 struct evsel *evsel __maybe_unused,507 struct evsel *evsel __maybe_unused,
511 struct hist_browser_timer *hbt __maybe_unused,508 struct hist_browser_timer *hbt __maybe_unused)
512 struct annotation_options *annotation_options __maybe_unused)
513{509{
514 return 0;510 return 0;
515}511}
516 512
517static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,513static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,
518 struct evsel *evsel __maybe_unused,514 struct evsel *evsel __maybe_unused,
519 struct hist_browser_timer *hbt __maybe_unused,515 struct hist_browser_timer *hbt __maybe_unused)
520 struct annotation_options *annotation_opts __maybe_unused)
521{516{
522 return 0;517 return 0;
523}518}
@@ -541,8 +536,7 @@ static inline void res_sample_init(void) {} · 17 unmodified lines
541static inline int block_hists_tui_browse(struct block_hist *bh __maybe_unused,536static inline int block_hists_tui_browse(struct block_hist *bh __maybe_unused,
542 struct evsel *evsel __maybe_unused,537 struct evsel *evsel __maybe_unused,
543 float min_percent __maybe_unused,538 float min_percent __maybe_unused,
544 struct perf_env *env __maybe_unused,539 struct perf_env *env __maybe_unused)
545 struct annotation_options *annotation_opts __maybe_unused)
546{540{
547 return 0;541 return 0;
548}542}
tools/perf/util/include/dwarf-regs.h+19−0
@@ -2,6 +2,9 @@ · 1 unmodified line
2#ifndef _PERF_DWARF_REGS_H_2#ifndef _PERF_DWARF_REGS_H_
3#define _PERF_DWARF_REGS_H_3#define _PERF_DWARF_REGS_H_
4 4
5#define DWARF_REG_PC 0xd3af9c /* random number */
6#define DWARF_REG_FB 0xd3affb /* random number */
7
5#ifdef HAVE_DWARF_SUPPORT8#ifdef HAVE_DWARF_SUPPORT
6const char *get_arch_regstr(unsigned int n);9const char *get_arch_regstr(unsigned int n);
7/*10/*
@@ -10,6 +13,22 @@ const char *get_arch_regstr(unsigned int n); · 2 unmodified lines
10 * machine: ELF machine signature (EM_*)13 * machine: ELF machine signature (EM_*)
11 */14 */
12const char *get_dwarf_regstr(unsigned int n, unsigned int machine);15const char *get_dwarf_regstr(unsigned int n, unsigned int machine);
16
17int 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 */
23int get_dwarf_regnum(const char *name, unsigned int machine);
24
25#else /* HAVE_DWARF_SUPPORT */
26
27static inline int get_dwarf_regnum(const char *name __maybe_unused,
28 unsigned int machine __maybe_unused)
29{
30 return -1;
31}
13#endif32#endif
14 33
15#ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET34#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
453 * Guest code can be found in hypervisor process at the same address453 * Guest code can be found in hypervisor process at the same address
454 * so copy host maps.454 * so copy host maps.
455 */455 */
456 err = maps__clone(thread, thread__maps(host_thread));456 err = maps__copy_from(thread__maps(thread), thread__maps(host_thread));
457 thread__put(host_thread);457 thread__put(host_thread);
458 if (err)458 if (err)
459 goto out_err;459 goto out_err;
@@ -1285,33 +1285,46 @@ static u64 find_entry_trampoline(struct dso *dso) · 825 unmodified lines
1285#define X86_64_CPU_ENTRY_AREA_SIZE 0x2c0001285#define X86_64_CPU_ENTRY_AREA_SIZE 0x2c000
1286#define X86_64_ENTRY_TRAMPOLINE 0x60001286#define X86_64_ENTRY_TRAMPOLINE 0x6000
1287 1287
1288struct machine__map_x86_64_entry_trampolines_args {
1289 struct maps *kmaps;
1290 bool found;
1291};
1292
1293static 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
1288/* Map x86_64 PTI entry trampolines */1310/* Map x86_64 PTI entry trampolines */
1289int machine__map_x86_64_entry_trampolines(struct machine *machine,1311int machine__map_x86_64_entry_trampolines(struct machine *machine,
1290 struct dso *kernel)1312 struct dso *kernel)
1291{1313{
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 };
1293 int nr_cpus_avail, cpu;1318 int nr_cpus_avail, cpu;
1294 bool found = false;
1295 struct map_rb_node *rb_node;
1296 u64 pgoff;1319 u64 pgoff;
1297 1320
1298 /*1321 /*
1299 * In the vmlinux case, pgoff is a virtual address which must now be1322 * In the vmlinux case, pgoff is a virtual address which must now be
1300 * mapped to a vmlinux offset.1323 * mapped to a vmlinux offset.
1301 */1324 */
1302 maps__for_each_entry(kmaps, rb_node) {1325 maps__for_each_map(args.kmaps, machine__map_x86_64_entry_trampolines_cb, &args);
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;
1308 1326
1309 dest_map = maps__find(kmaps, map__pgoff(map));1327 if (args.found || machine->trampolines_mapped)
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)
1315 return 0;1328 return 0;
1316 1329
1317 pgoff = find_entry_trampoline(kernel);1330 pgoff = find_entry_trampoline(kernel);
@@ -1359,8 +1372,7 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) · 41 unmodified lines
1359 if (machine->vmlinux_map == NULL)1372 if (machine->vmlinux_map == NULL)
1360 return -ENOMEM;1373 return -ENOMEM;
1361 1374
1362 map__set_map_ip(machine->vmlinux_map, identity__map_ip);1375 map__set_mapping_type(machine->vmlinux_map, MAPPING_TYPE__IDENTITY);
1363 map__set_unmap_ip(machine->vmlinux_map, identity__map_ip);
1364 return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map);1376 return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map);
1365}1377}
1366 1378
@@ -1750,12 +1762,11 @@ int machine__create_kernel_maps(struct machine *machine) · 383 unmodified lines
1750 1762
1751 if (end == ~0ULL) {1763 if (end == ~0ULL) {
1752 /* update end address of the kernel map using adjacent module address */1764 /* 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),1765 struct map *next = maps__find_next_entry(machine__kernel_maps(machine),
1754 machine__kernel_map(machine));1766 machine__kernel_map(machine));
1755 struct map_rb_node *next = map_rb_node__next(rb_node);
1756 1767
1757 if (next)1768 if (next)
1758 machine__set_kernel_mmap(machine, start, map__start(next->map));1769 machine__set_kernel_mmap(machine, start, map__start(next));
1759 }1770 }
1760 1771
1761out_put:1772out_put:
@@ -2157,9 +2168,13 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event · 395 unmodified lines
2157 if (dump_trace)2168 if (dump_trace)
2158 perf_event__fprintf_task(event, stdout);2169 perf_event__fprintf_task(event, stdout);
2159 2170
2160 if (thread != NULL)2171 if (thread != NULL) {
2161 thread__put(thread);2172 if (symbol_conf.keep_exited_threads)
2162 2173 thread__set_exited(thread, /*exited=*/true);
2174 else
2175 machine__remove_thread(machine, thread);
2176 }
2177 thread__put(thread);
2163 return 0;2178 return 0;
2164}2179}
2165 2180
@@ -3395,16 +3410,8 @@ int machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv · 1229 unmodified lines
3395int machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv)3410int machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv)
3396{3411{
3397 struct maps *maps = machine__kernel_maps(machine);3412 struct maps *maps = machine__kernel_maps(machine);
3398 struct map_rb_node *pos;
3399 int err = 0;
3400 3413
3401 maps__for_each_entry(maps, pos) {3414 return maps__for_each_map(maps, fn, priv);
3402 err = fn(pos->map, priv);
3403 if (err != 0) {
3404 break;
3405 }
3406 }
3407 return err;
3408}3415}
3409 3416
3410bool machine__is_lock_function(struct machine *machine, u64 addr)3417bool 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
109 map__set_pgoff(map, pgoff);109 map__set_pgoff(map, pgoff);
110 map__set_reloc(map, 0);110 map__set_reloc(map, 0);
111 map__set_dso(map, dso__get(dso));111 map__set_dso(map, dso__get(dso));
112 map__set_map_ip(map, map__dso_map_ip);112 map__set_mapping_type(map, MAPPING_TYPE__DSO);
113 map__set_unmap_ip(map, map__dso_unmap_ip);
114 map__set_erange_warned(map, false);113 map__set_erange_warned(map, false);
115 refcount_set(map__refcnt(map), 1);114 refcount_set(map__refcnt(map), 1);
116}115}
@@ -172,7 +171,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, · 55 unmodified lines
172 map__init(result, start, start + len, pgoff, dso);171 map__init(result, start, start + len, pgoff, dso);
173 172
174 if (anon || no_dso) {173 if (anon || no_dso) {
175 map->map_ip = map->unmap_ip = identity__map_ip;174 map->mapping_type = MAPPING_TYPE__IDENTITY;
176 175
177 /*176 /*
178 * Set memory without DSO as loaded. All map__find_*177 * Set memory without DSO as loaded. All map__find_*
@@ -630,18 +629,3 @@ struct maps *map__kmaps(struct map *map) · 451 unmodified lines
630 }629 }
631 return kmap->kmaps;630 return kmap->kmaps;
632}631}
633
634u64 map__dso_map_ip(const struct map *map, u64 ip)
635{
636 return ip - map__start(map) + map__pgoff(map);
637}
638
639u64 map__dso_unmap_ip(const struct map *map, u64 ip)
640{
641 return ip + map__start(map) - map__pgoff(map);
642}
643
644u64 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
16struct maps;16struct maps;
17struct machine;17struct machine;
18 18
19enum 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
19DECLARE_RC_STRUCT(map) {26DECLARE_RC_STRUCT(map) {
20 u64 start;27 u64 start;
21 u64 end;28 u64 end;
22 bool erange_warned:1;
23 bool priv:1;
24 u32 prot;
25 u64 pgoff;29 u64 pgoff;
26 u64 reloc;30 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
33 struct dso *dso;31 struct dso *dso;
34 refcount_t refcnt;32 refcount_t refcnt;
33 u32 prot;
35 u32 flags;34 u32 flags;
35 enum mapping_type mapping_type:8;
36 bool erange_warned;
37 bool priv;
36};38};
37 39
38struct kmap;40struct kmap;
@@ -41,38 +43,11 @@ struct kmap *__map__kmap(struct map *map); · 2 unmodified lines
41struct kmap *map__kmap(struct map *map);43struct kmap *map__kmap(struct map *map);
42struct maps *map__kmaps(struct map *map);44struct maps *map__kmaps(struct map *map);
43 45
44/* ip -> dso rip */
45u64 map__dso_map_ip(const struct map *map, u64 ip);
46/* dso rip -> ip */
47u64 map__dso_unmap_ip(const struct map *map, u64 ip);
48/* Returns ip */
49u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip);
50
51static inline struct dso *map__dso(const struct map *map)46static inline struct dso *map__dso(const struct map *map)
52{47{
53 return RC_CHK_ACCESS(map)->dso;48 return RC_CHK_ACCESS(map)->dso;
54}49}
55 50
56static inline u64 map__map_ip(const struct map *map, u64 ip)
57{
58 return RC_CHK_ACCESS(map)->map_ip(map, ip);
59}
60
61static inline u64 map__unmap_ip(const struct map *map, u64 ip)
62{
63 return RC_CHK_ACCESS(map)->unmap_ip(map, ip);
64}
65
66static inline void *map__map_ip_ptr(struct map *map)
67{
68 return RC_CHK_ACCESS(map)->map_ip;
69}
70
71static inline void* map__unmap_ip_ptr(struct map *map)
72{
73 return RC_CHK_ACCESS(map)->unmap_ip;
74}
75
76static inline u64 map__start(const struct map *map)51static inline u64 map__start(const struct map *map)
77{52{
78 return RC_CHK_ACCESS(map)->start;53 return RC_CHK_ACCESS(map)->start;
@@ -123,6 +98,34 @@ static inline size_t map__size(const struct map *map) · 44 unmodified lines
123 return map__end(map) - map__start(map);98 return map__end(map) - map__start(map);
124}99}
125 100
101/* ip -> dso rip */
102static 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 */
108static inline u64 map__dso_unmap_ip(const struct map *map, u64 rip)
109{
110 return rip + map__start(map) - map__pgoff(map);
111}
112
113static 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
121static 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
126/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */129/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
127u64 map__rip_2objdump(struct map *map, u64 rip);130u64 map__rip_2objdump(struct map *map, u64 rip);
128 131
@@ -294,13 +297,13 @@ static inline void map__set_dso(struct map *map, struct dso *dso) · 165 unmodified lines
294 RC_CHK_ACCESS(map)->dso = dso;297 RC_CHK_ACCESS(map)->dso = dso;
295}298}
296 299
297static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip))300static inline void map__set_mapping_type(struct map *map, enum mapping_type type)
298{301{
299 RC_CHK_ACCESS(map)->map_ip = map_ip;302 RC_CHK_ACCESS(map)->mapping_type = type;
300}303}
301 304
302static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip))305static inline enum mapping_type map__mapping_type(struct map *map)
303{306{
304 RC_CHK_ACCESS(map)->unmap_ip = unmap_ip;307 return RC_CHK_ACCESS(map)->mapping_type;
305}308}
306#endif /* __PERF_MAP_H */309#endif /* __PERF_MAP_H */
tools/perf/util/maps.c+445−83
@@ -10,6 +10,68 @@ · 9 unmodified lines
10#include "ui/ui.h"10#include "ui/ui.h"
11#include "unwind.h"11#include "unwind.h"
12 12
13struct 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
25static struct rb_root *maps__entries(struct maps *maps)
26{
27 return &RC_CHK_ACCESS(maps)->entries;
28}
29
30static struct rw_semaphore *maps__lock(struct maps *maps)
31{
32 return &RC_CHK_ACCESS(maps)->lock;
33}
34
35static struct map **maps__maps_by_name(struct maps *maps)
36{
37 return RC_CHK_ACCESS(maps)->maps_by_name;
38}
39
40static 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
49static 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
64static 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
13static void maps__init(struct maps *maps, struct machine *machine)75static void maps__init(struct maps *maps, struct machine *machine)
14{76{
15 refcount_set(maps__refcnt(maps), 1);77 refcount_set(maps__refcnt(maps), 1);
@@ -196,6 +258,41 @@ void maps__put(struct maps *maps) · 180 unmodified lines
196 RC_CHK_PUT(maps);258 RC_CHK_PUT(maps);
197}259}
198 260
261int 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
276void 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
199struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)296struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
200{297{
201 struct map *map = maps__find(maps, addr);298 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
210 return NULL;307 return NULL;
211}308}
212 309
213struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp)310struct maps__find_symbol_by_name_args {
214{311 struct map **mapp;
312 const char *name;
215 struct symbol *sym;313 struct symbol *sym;
216 struct map_rb_node *pos;314};
217 315
218 down_read(maps__lock(maps));316static int maps__find_symbol_by_name_cb(struct map *map, void *data)
317{
318 struct maps__find_symbol_by_name_args *args = data;
219 319
220 maps__for_each_entry(maps, pos) {320 args->sym = map__find_symbol_by_name(map, args->name);
221 sym = map__find_symbol_by_name(pos->map, name);321 if (!args->sym)
322 return 0;
222 323
223 if (sym == NULL)324 if (!map__contains_symbol(map, args->sym)) {
224 continue;325 args->sym = NULL;
225 if (!map__contains_symbol(pos->map, sym)) {326 return 0;
226 sym = NULL;
227 continue;
228 }
229 if (mapp != NULL)
230 *mapp = pos->map;
231 goto out;
232 }327 }
233 328
234 sym = NULL;329 if (args->mapp != NULL)
235out:330 *args->mapp = map__get(map);
236 up_read(maps__lock(maps));331 return 1;
237 return sym;332}
333
334struct 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;
238}344}
239 345
240int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)346int 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
253 return ams->ms.sym ? 0 : -1;359 return ams->ms.sym ? 0 : -1;
254}360}
255 361
256size_t maps__fprintf(struct maps *maps, FILE *fp)362struct maps__fprintf_args {
257{363 FILE *fp;
258 size_t printed = 0;364 size_t printed;
259 struct map_rb_node *pos;365};
260 366
261 down_read(maps__lock(maps));367static int maps__fprintf_cb(struct map *map, void *data)
368{
369 struct maps__fprintf_args *args = data;
262 370
263 maps__for_each_entry(maps, pos) {371 args->printed += fprintf(args->fp, "Map:");
264 printed += fprintf(fp, "Map:");372 args->printed += map__fprintf(map, args->fp);
265 printed += map__fprintf(pos->map, fp);373 if (verbose > 2) {
266 if (verbose > 2) {374 args->printed += dso__fprintf(map__dso(map), args->fp);
267 printed += dso__fprintf(map__dso(pos->map), fp);375 args->printed += fprintf(args->fp, "--\n");
268 printed += fprintf(fp, "--\n");
269 }
270 }376 }
377 return 0;
378}
271 379
272 up_read(maps__lock(maps));380size_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);
273 388
274 return printed;389 return args.printed;
275}390}
276 391
277int 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 */
396static struct rb_node *first_ending_after(struct maps *maps, const struct map *map)
278{397{
279 struct rb_root *root;398 struct rb_root *root;
280 struct rb_node *next, *first;399 struct rb_node *next, *first;
281 int err = 0;
282
283 down_write(maps__lock(maps));
284 400
285 root = maps__entries(maps);401 root = maps__entries(maps);
286
287 /*
288 * Find first map where end > map->start.
289 * Same as find_vma() in kernel.
290 */
291 next = root->rb_node;402 next = root->rb_node;
292 first = NULL;403 first = NULL;
293 while (next) {404 while (next) {
@@ -301,8 +412,23 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 7 unmodified lines
301 } else412 } else
302 next = next->rb_right;413 next = next->rb_right;
303 }414 }
415 return first;
416}
304 417
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 */
422int 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);
306 while (next && !err) {432 while (next && !err) {
307 struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node);433 struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node);
308 next = rb_next(&pos->rb_node);434 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
311 * Stop if current map starts after map->end.437 * Stop if current map starts after map->end.
312 * Maps are ordered by start: next will not overlap for sure.438 * Maps are ordered by start: next will not overlap for sure.
313 */439 */
314 if (map__start(pos->map) >= map__end(map))440 if (map__start(pos->map) >= map__end(new))
315 break;441 break;
316 442
317 if (verbose >= 2) {443 if (verbose >= 2) {
318 444
319 if (use_browser) {445 if (use_browser) {
320 pr_debug("overlapping maps in %s (disable tui for more info)\n",446 pr_debug("overlapping maps in %s (disable tui for more info)\n",
321 map__dso(map)->name);447 map__dso(new)->name);
322 } else {448 } else {
323 fputs("overlapping maps:\n", fp);449 pr_debug("overlapping maps:\n");
324 map__fprintf(map, fp);450 map__fprintf(new, fp);
325 map__fprintf(pos->map, fp);451 map__fprintf(pos->map, fp);
326 }452 }
327 }453 }
328 454
329 rb_erase_init(&pos->rb_node, root);455 rb_erase_init(&pos->rb_node, maps__entries(maps));
330 /*456 /*
331 * Now check if we need to create new maps for areas not457 * Now check if we need to create new maps for areas not
332 * overlapped by the new map:458 * overlapped by the new map:
333 */459 */
334 if (map__start(map) > map__start(pos->map)) {460 if (map__start(new) > map__start(pos->map)) {
335 struct map *before = map__clone(pos->map);461 struct map *before = map__clone(pos->map);
336 462
337 if (before == NULL) {463 if (before == NULL) {
@@ -339,7 +465,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 1 unmodified line
339 goto put_map;465 goto put_map;
340 }466 }
341 467
342 map__set_end(before, map__start(map));468 map__set_end(before, map__start(new));
343 err = __maps__insert(maps, before);469 err = __maps__insert(maps, before);
344 if (err) {470 if (err) {
345 map__put(before);471 map__put(before);
@@ -351,7 +477,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 5 unmodified lines
351 map__put(before);477 map__put(before);
352 }478 }
353 479
354 if (map__end(map) < map__end(pos->map)) {480 if (map__end(new) < map__end(pos->map)) {
355 struct map *after = map__clone(pos->map);481 struct map *after = map__clone(pos->map);
356 482
357 if (after == NULL) {483 if (after == NULL) {
@@ -359,10 +485,10 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 1 unmodified line
359 goto put_map;485 goto put_map;
360 }486 }
361 487
362 map__set_start(after, map__end(map));488 map__set_start(after, map__end(new));
363 map__add_pgoff(after, map__end(map) - map__start(pos->map));489 map__add_pgoff(after, map__end(new) - map__start(pos->map));
364 assert(map__map_ip(pos->map, map__end(map)) ==490 assert(map__map_ip(pos->map, map__end(new)) ==
365 map__map_ip(after, map__end(map)));491 map__map_ip(after, map__end(new)));
366 err = __maps__insert(maps, after);492 err = __maps__insert(maps, after);
367 if (err) {493 if (err) {
368 map__put(after);494 map__put(after);
@@ -376,16 +502,14 @@ put_map: · 7 unmodified lines
376 map__put(pos->map);502 map__put(pos->map);
377 free(pos);503 free(pos);
378 }504 }
505 /* Add the map. */
506 err = __maps__insert(maps, new);
379 up_write(maps__lock(maps));507 up_write(maps__lock(maps));
380 return err;508 return err;
381}509}
382 510
383/*511int maps__copy_from(struct maps *maps, struct maps *parent)
384 * XXX This should not really _copy_ te maps, but refcount them.
385 */
386int maps__clone(struct thread *thread, struct maps *parent)
387{512{
388 struct maps *maps = thread__maps(thread);
389 int err;513 int err;
390 struct map_rb_node *rb_node;514 struct map_rb_node *rb_node;
391 515
@@ -416,17 +540,6 @@ out_unlock: · 24 unmodified lines
416 return err;540 return err;
417}541}
418 542
419struct 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
430struct map *maps__find(struct maps *maps, u64 ip)543struct map *maps__find(struct maps *maps, u64 ip)
431{544{
432 struct rb_node *p;545 struct rb_node *p;
@@ -452,26 +565,275 @@ out: · 19 unmodified lines
452 return m ? m->map : NULL;565 return m ? m->map : NULL;
453}566}
454 567
455struct map_rb_node *maps__first(struct maps *maps)568static int map__strcmp(const void *a, const void *b)
456{569{
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);
458 575
459 if (first)576 if (ret == 0 && map_a != map_b) {
460 return rb_entry(first, struct map_rb_node, rb_node);577 /*
461 return NULL;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;
462}587}
463 588
464struct map_rb_node *map_rb_node__next(struct map_rb_node *node)589static int map__strcmp_name(const void *name, const void *b)
465{590{
466 struct rb_node *next;591 const struct dso *dso = map__dso(*(const struct map **)b);
467 592
468 if (!node)593 return strcmp(name, dso->short_name);
469 return NULL;594}
470 595
471 next = rb_next(&node->rb_node);596void __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}
472 600
473 if (!next)601static 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
628static 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))
474 return NULL;634 return NULL;
475 635
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
643struct 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
681out_unlock:
682 up_read(maps__lock(maps));
683 return map;
684}
685
686struct 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
697void 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 */
724int 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
808out:
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
828void 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));
477}839}
tools/perf/util/maps.h+19−29
@@ -14,24 +14,18 @@ struct ref_reloc_sym; · 13 unmodified lines
14struct machine;14struct machine;
15struct map;15struct map;
16struct maps;16struct maps;
17struct thread;
18 17
19struct map_rb_node {18struct map_list_node {
20 struct rb_node rb_node;19 struct list_head node;
21 struct map *map;20 struct map *map;
22};21};
23 22
24struct map_rb_node *maps__first(struct maps *maps);23static inline struct map_list_node *map_list_node__new(void)
25struct map_rb_node *map_rb_node__next(struct map_rb_node *node);24{
26struct map_rb_node *maps__find_node(struct maps *maps, struct map *map);25 return malloc(sizeof(struct map_list_node));
27struct map *maps__find(struct maps *maps, u64 addr);26}
28
29#define maps__for_each_entry(maps, map) \
30 for (map = maps__first(maps); map; map = map_rb_node__next(map))
31 27
32#define maps__for_each_entry_safe(maps, map, next) \28struct map *maps__find(struct maps *maps, u64 addr);
33 for (map = maps__first(maps), next = map_rb_node__next(map); map; \
34 map = next, next = map_rb_node__next(map))
35 29
36DECLARE_RC_STRUCT(maps) {30DECLARE_RC_STRUCT(maps) {
37 struct rb_root entries;31 struct rb_root entries;
@@ -58,7 +52,7 @@ struct kmap { · 20 unmodified lines
58 52
59struct maps *maps__new(struct machine *machine);53struct maps *maps__new(struct machine *machine);
60bool maps__empty(struct maps *maps);54bool maps__empty(struct maps *maps);
61int maps__clone(struct thread *thread, struct maps *parent);55int maps__copy_from(struct maps *maps, struct maps *parent);
62 56
63struct maps *maps__get(struct maps *maps);57struct maps *maps__get(struct maps *maps);
64void maps__put(struct maps *maps);58void maps__put(struct maps *maps);
@@ -71,26 +65,16 @@ static inline void __maps__zput(struct maps **map) · 6 unmodified lines
71 65
72#define maps__zput(map) __maps__zput(&map)66#define maps__zput(map) __maps__zput(&map)
73 67
74static inline struct rb_root *maps__entries(struct maps *maps)68/* Iterate over map calling cb for each entry. */
75{69int maps__for_each_map(struct maps *maps, int (*cb)(struct map *map, void *data), void *data);
76 return &RC_CHK_ACCESS(maps)->entries;70/* Iterate over map removing an entry if cb returns true. */
77}71void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data);
78 72
79static inline struct machine *maps__machine(struct maps *maps)73static inline struct machine *maps__machine(struct maps *maps)
80{74{
81 return RC_CHK_ACCESS(maps)->machine;75 return RC_CHK_ACCESS(maps)->machine;
82}76}
83 77
84static inline struct rw_semaphore *maps__lock(struct maps *maps)
85{
86 return &RC_CHK_ACCESS(maps)->lock;
87}
88
89static inline struct map **maps__maps_by_name(struct maps *maps)
90{
91 return RC_CHK_ACCESS(maps)->maps_by_name;
92}
93
94static inline unsigned int maps__nr_maps(const struct maps *maps)78static inline unsigned int maps__nr_maps(const struct maps *maps)
95{79{
96 return RC_CHK_ACCESS(maps)->nr_maps;80 return RC_CHK_ACCESS(maps)->nr_maps;
@@ -125,12 +109,18 @@ struct addr_map_symbol; · 28 unmodified lines
125 109
126int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams);110int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams);
127 111
128int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp);112int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new);
129 113
130struct map *maps__find_by_name(struct maps *maps, const char *name);114struct map *maps__find_by_name(struct maps *maps, const char *name);
131 115
116struct map *maps__find_next_entry(struct maps *maps, struct map *map);
117
132int maps__merge_in(struct maps *kmaps, struct map *new_map);118int maps__merge_in(struct maps *kmaps, struct map *new_map);
133 119
134void __maps__sort_by_name(struct maps *maps);120void __maps__sort_by_name(struct maps *maps);
135 121
122void maps__fixup_end(struct maps *maps);
123
124void maps__load_first(struct maps *maps);
125
136#endif // __PERF_MAPS_H126#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
100 return -1;100 return -1;
101}101}
102 102
103static bool perf_mem_event__supported(const char *mnt, char *sysfs_name)103static bool perf_mem_event__supported(const char *mnt, struct perf_pmu *pmu,
104 struct perf_mem_event *e)
104{105{
106 char sysfs_name[100];
105 char path[PATH_MAX];107 char path[PATH_MAX];
106 struct stat st;108 struct stat st;
107 109
110 scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name);
108 scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);111 scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);
109 return !stat(path, &st);112 return !stat(path, &st);
110}113}
@@ -120,7 +123,6 @@ int perf_mem_events__init(void) · 9 unmodified lines
120 123
121 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {124 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
122 struct perf_mem_event *e = perf_mem_events__ptr(j);125 struct perf_mem_event *e = perf_mem_events__ptr(j);
123 char sysfs_name[100];
124 struct perf_pmu *pmu = NULL;126 struct perf_pmu *pmu = NULL;
125 127
126 /*128 /*
@@ -136,12 +138,12 @@ int perf_mem_events__init(void) · 9 unmodified lines
136 * of core PMU.138 * of core PMU.
137 */139 */
138 while ((pmu = perf_pmus__scan(pmu)) != NULL) {140 while ((pmu = perf_pmus__scan(pmu)) != NULL) {
139 scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name);141 e->supported |= perf_mem_event__supported(mnt, pmu, e);
140 e->supported |= perf_mem_event__supported(mnt, sysfs_name);142 if (e->supported) {
143 found = true;
144 break;
145 }
141 }146 }
142
143 if (e->supported)
144 found = true;
145 }147 }
146 148
147 return found ? 0 : -ENOENT;149 return found ? 0 : -ENOENT;
@@ -167,13 +169,10 @@ static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, · 19 unmodified lines
167 int idx)169 int idx)
168{170{
169 const char *mnt = sysfs__mount();171 const char *mnt = sysfs__mount();
170 char sysfs_name[100];
171 struct perf_pmu *pmu = NULL;172 struct perf_pmu *pmu = NULL;
172 173
173 while ((pmu = perf_pmus__scan(pmu)) != NULL) {174 while ((pmu = perf_pmus__scan(pmu)) != NULL) {
174 scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name,175 if (!perf_mem_event__supported(mnt, pmu, e)) {
175 pmu->name);
176 if (!perf_mem_event__supported(mnt, sysfs_name)) {
177 pr_err("failed: event '%s' not supported\n",176 pr_err("failed: event '%s' not supported\n",
178 perf_mem_events__name(idx, pmu->name));177 perf_mem_events__name(idx, pmu->name));
179 }178 }
@@ -183,6 +182,7 @@ static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, · 3 unmodified lines
183int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,182int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
184 char **rec_tmp, int *tmp_nr)183 char **rec_tmp, int *tmp_nr)
185{184{
185 const char *mnt = sysfs__mount();
186 int i = *argv_nr, k = 0;186 int i = *argv_nr, k = 0;
187 struct perf_mem_event *e;187 struct perf_mem_event *e;
188 188
@@ -211,6 +211,9 @@ int perf_mem_events__record_args(const char **rec_argv, int *argv_nr, · 22 unmodified lines
211 while ((pmu = perf_pmus__scan(pmu)) != NULL) {211 while ((pmu = perf_pmus__scan(pmu)) != NULL) {
212 const char *s = perf_mem_events__name(j, pmu->name);212 const char *s = perf_mem_events__name(j, pmu->name);
213 213
214 if (!perf_mem_event__supported(mnt, pmu, e))
215 continue;
216
214 rec_argv[i++] = "-e";217 rec_argv[i++] = "-e";
215 if (s) {218 if (s) {
216 char *copy = strdup(s);219 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
295 295
296 map->core.flush = mp->flush;296 map->core.flush = mp->flush;
297 297
298 map->comp_level = mp->comp_level;
299#ifndef PYTHON_PERF298#ifndef PYTHON_PERF
300 if (zstd_init(&map->zstd_data, map->comp_level)) {299 if (zstd_init(&map->zstd_data, mp->comp_level)) {
301 pr_debug2("failed to init mmap compressor, error %d\n", errno);300 pr_debug2("failed to init mmap compressor, error %d\n", errno);
302 return -1;301 return -1;
303 }302 }
304#endif303#endif
305 304
306 if (map->comp_level && !perf_mmap__aio_enabled(map)) {305 if (mp->comp_level && !perf_mmap__aio_enabled(map)) {
307 map->data = mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE,306 map->data = mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE,
308 MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);307 MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
309 if (map->data == MAP_FAILED) {308 if (map->data == MAP_FAILED) {
tools/perf/util/mmap.h+0−1
@@ -39,7 +39,6 @@ struct mmap { · 38 unmodified lines
39#endif39#endif
40 struct mmap_cpu_mask affinity_mask;40 struct mmap_cpu_mask affinity_mask;
41 void *data;41 void *data;
42 int comp_level;
43 struct perf_data_file *file;42 struct perf_data_file *file;
44 struct zstd_data zstd_data;43 struct zstd_data zstd_data;
45};44};
tools/perf/util/parse-branch-options.c+1−0
@@ -36,6 +36,7 @@ static const struct branch_mode branch_modes[] = { · 35 unmodified lines
36 BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK),36 BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK),
37 BRANCH_OPT("hw_index", PERF_SAMPLE_BRANCH_HW_INDEX),37 BRANCH_OPT("hw_index", PERF_SAMPLE_BRANCH_HW_INDEX),
38 BRANCH_OPT("priv", PERF_SAMPLE_BRANCH_PRIV_SAVE),38 BRANCH_OPT("priv", PERF_SAMPLE_BRANCH_PRIV_SAVE),
39 BRANCH_OPT("counter", PERF_SAMPLE_BRANCH_COUNTERS),
39 BRANCH_END40 BRANCH_END
40};41};
41 42
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
976 struct parse_events_error *err)976 struct parse_events_error *err)
977{977{
978 if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) {978 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);
980 980
981 if (!pmu) {981 if (!pmu) {
982 char *err_str;982 char *err_str;
@@ -986,15 +986,23 @@ static int config_term_pmu(struct perf_event_attr *attr, · 3 unmodified lines
986 err_str, /*help=*/NULL);986 err_str, /*help=*/NULL);
987 return -EINVAL;987 return -EINVAL;
988 }988 }
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)) {
990 attr->type = PERF_TYPE_HW_CACHE;996 attr->type = PERF_TYPE_HW_CACHE;
991 return parse_events__decode_legacy_cache(term->config, pmu->type,997 return parse_events__decode_legacy_cache(term->config, pmu->type,
992 &attr->config);998 &attr->config);
993 } else999 } else {
994 term->type_term = PARSE_EVENTS__TERM_TYPE_USER;1000 term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
1001 term->no_value = true;
1002 }
995 }1003 }
996 if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) {1004 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);
998 1006
999 if (!pmu) {1007 if (!pmu) {
1000 char *err_str;1008 char *err_str;
@@ -1004,10 +1012,19 @@ static int config_term_pmu(struct perf_event_attr *attr, · 3 unmodified lines
1004 err_str, /*help=*/NULL);1012 err_str, /*help=*/NULL);
1005 return -EINVAL;1013 return -EINVAL;
1006 }1014 }
1007 attr->type = PERF_TYPE_HARDWARE;1015 /*
1008 attr->config = term->val.num;1016 * If the PMU has a sysfs or json event prefer it over
1009 if (perf_pmus__supports_extended_type())1017 * legacy. ARM requires this.
1010 attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;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 }
1011 return 0;1028 return 0;
1012 }1029 }
1013 if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER ||1030 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
1381 YYLTYPE *loc = loc_;1398 YYLTYPE *loc = loc_;
1382 LIST_HEAD(config_terms);1399 LIST_HEAD(config_terms);
1383 struct parse_events_terms parsed_terms;1400 struct parse_events_terms parsed_terms;
1401 bool alias_rewrote_terms = false;
1384 1402
1385 pmu = parse_state->fake_pmu ?: perf_pmus__find(name);1403 pmu = parse_state->fake_pmu ?: perf_pmus__find(name);
1386 1404
@@ -1433,7 +1451,15 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, · 46 unmodified lines
1433 return evsel ? 0 : -ENOMEM;1451 return evsel ? 0 : -ENOMEM;
1434 }1452 }
1435 1453
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)) {
1437 parse_events_terms__exit(&parsed_terms);1463 parse_events_terms__exit(&parsed_terms);
1438 return -EINVAL;1464 return -EINVAL;
1439 }1465 }
@@ -1447,11 +1473,9 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, · 7 unmodified lines
1447 strbuf_release(&sb);1473 strbuf_release(&sb);
1448 }1474 }
1449 1475
1450 /*1476 /* Configure attr/terms again if an alias was expanded. */
1451 * Configure hardcoded terms first, no need to check1477 if (alias_rewrote_terms &&
1452 * return value when called with fail == 0 ;)1478 config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) {
1453 */
1454 if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) {
1455 parse_events_terms__exit(&parsed_terms);1479 parse_events_terms__exit(&parsed_terms);
1456 return -EINVAL;1480 return -EINVAL;
1457 }1481 }
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
64 struct perf_cpu cpu;64 struct perf_cpu cpu;
65 int ret, i = 0;65 int ret, i = 0;
66 66
67 cpus = perf_cpu_map__new(NULL);67 cpus = perf_cpu_map__new_online_cpus();
68 if (!cpus)68 if (!cpus)
69 return false;69 return false;
70 cpu = perf_cpu_map__cpu(cpus, 0);70 cpu = perf_cpu_map__cpu(cpus, 0);
@@ -140,7 +140,7 @@ bool perf_can_record_cpu_wide(void) · 69 unmodified lines
140 struct perf_cpu cpu;140 struct perf_cpu cpu;
141 int fd;141 int fd;
142 142
143 cpus = perf_cpu_map__new(NULL);143 cpus = perf_cpu_map__new_online_cpus();
144 if (!cpus)144 if (!cpus)
145 return false;145 return false;
146 146
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
55 bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),55 bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
56 bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),56 bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
57 bit_name(TYPE_SAVE), bit_name(HW_INDEX), bit_name(PRIV_SAVE),57 bit_name(TYPE_SAVE), bit_name(HW_INDEX), bit_name(PRIV_SAVE),
58 bit_name(COUNTERS),
58 { .name = NULL, }59 { .name = NULL, }
59 };60 };
60#undef bit_name61#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
1494 * defined for the alias1494 * defined for the alias
1495 */1495 */
1496int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,1496int 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)
1498{1499{
1499 struct parse_events_term *term, *h;1500 struct parse_events_term *term, *h;
1500 struct perf_pmu_alias *alias;1501 struct perf_pmu_alias *alias;
1501 int ret;1502 int ret;
1502 1503
1504 *rewrote_terms = false;
1503 info->per_pkg = false;1505 info->per_pkg = false;
1504 1506
1505 /*1507 /*
@@ -1521,7 +1523,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ · 15 unmodified lines
1521 NULL);1523 NULL);
1522 return ret;1524 return ret;
1523 }1525 }
1524 1526 *rewrote_terms = true;
1525 ret = check_info_data(pmu, alias, info, err, term->err_term);1527 ret = check_info_data(pmu, alias, info, err, term->err_term);
1526 if (ret)1528 if (ret)
1527 return ret;1529 return ret;
@@ -1615,6 +1617,8 @@ bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu) · 87 unmodified lines
1615 1617
1616bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)1618bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
1617{1619{
1620 if (!name)
1621 return false;
1618 if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)1622 if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
1619 return true;1623 return true;
1620 if (pmu->cpu_aliases_added || !pmu->events_table)1624 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
201__u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name);201__u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name);
202int perf_pmu__format_type(struct perf_pmu *pmu, const char *name);202int perf_pmu__format_type(struct perf_pmu *pmu, const char *name);
203int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,203int 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);
205int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);206int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);
206 207
207int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load);208int 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
149 return 0;149 return 0;
150}150}
151 151
152struct kernel_get_module_map_cb_args {
153 const char *module;
154 struct map *result;
155};
156
157static 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
152static struct map *kernel_get_module_map(const char *module)172static struct map *kernel_get_module_map(const char *module)
153{173{
154 struct maps *maps = machine__kernel_maps(host_machine);174 struct kernel_get_module_map_cb_args args = {
155 struct map_rb_node *pos;175 .module = module,
176 .result = NULL,
177 };
156 178
157 /* A file path -- this is an offline module */179 /* A file path -- this is an offline module */
158 if (module && strchr(module, '/'))180 if (module && strchr(module, '/'))
@@ -164,19 +186,9 @@ static struct map *kernel_get_module_map(const char *module) · 5 unmodified lines
164 return map__get(map);186 return map__get(map);
165 }187 }
166 188
167 maps__for_each_entry(maps, pos) {189 maps__for_each_map(machine__kernel_maps(host_machine), kernel_get_module_map_cb, &args);
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;
172 190
173 if (strncmp(short_name + 1, module,191 return args.result;
174 short_name_len - 2) == 0 &&
175 module[short_name_len - 2] == '\0') {
176 return map__get(pos->map);
177 }
178 }
179 return NULL;
180}192}
181 193
182struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)194struct 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
23#include "event.h"23#include "event.h"
24#include "dso.h"24#include "dso.h"
25#include "debug.h"25#include "debug.h"
26#include "debuginfo.h"
26#include "intlist.h"27#include "intlist.h"
27#include "strbuf.h"28#include "strbuf.h"
28#include "strlist.h"29#include "strlist.h"
@@ -31,128 +32,9 @@ · 2 unmodified lines
31#include "probe-file.h"32#include "probe-file.h"
32#include "string2.h"33#include "string2.h"
33 34
34#ifdef HAVE_DEBUGINFOD_SUPPORT
35#include <elfutils/debuginfod.h>
36#endif
37
38/* Kprobe tracer basic type is up to u64 */35/* Kprobe tracer basic type is up to u64 */
39#define MAX_BASIC_TYPE_BITS 6436#define MAX_BASIC_TYPE_BITS 64
40 37
41/* Dwarf FL wrappers */
42static char *debuginfo_path; /* Currently dummy */
43
44static 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 */
55static 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;
83error:
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
93static 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
106enum 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
115struct 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
142out:
143 /* if failed to open all distro debuginfo, open given binary */
144 return dinfo ? : __debuginfo__new(path);
145}
146
147void debuginfo__delete(struct debuginfo *dbg)
148{
149 if (dbg) {
150 if (dbg->dwfl)
151 dwfl_end(dbg->dwfl);
152 free(dbg);
153 }
154}
155
156/*38/*
157 * Probe finder related functions39 * Probe finder related functions
158 */40 */
@@ -722,7 +604,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) · 563 unmodified lines
722 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);604 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
723 if (ret <= 0 || nops == 0) {605 if (ret <= 0 || nops == 0) {
724 pf->fb_ops = NULL;606 pf->fb_ops = NULL;
725#if _ELFUTILS_PREREQ(0, 142)607#ifdef HAVE_DWARF_CFI_SUPPORT
726 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&608 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
727 (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {609 (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
728 if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&610 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
733 free(frame);615 free(frame);
734 return -ENOENT;616 return -ENOENT;
735 }617 }
736#endif618#endif /* HAVE_DWARF_CFI_SUPPORT */
737 }619 }
738 620
739 /* Call finder's callback handler */621 /* Call finder's callback handler */
@@ -1258,7 +1140,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, · 518 unmodified lines
1258 1140
1259 pf->machine = ehdr.e_machine;1141 pf->machine = ehdr.e_machine;
1260 1142
1261#if _ELFUTILS_PREREQ(0, 142)1143#ifdef HAVE_DWARF_CFI_SUPPORT
1262 do {1144 do {
1263 GElf_Shdr shdr;1145 GElf_Shdr shdr;
1264 1146
@@ -1268,7 +1150,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, · 3 unmodified lines
1268 1150
1269 pf->cfi_dbg = dwarf_getcfi(dbg->dbg);1151 pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
1270 } while (0);1152 } while (0);
1271#endif1153#endif /* HAVE_DWARF_CFI_SUPPORT */
1272 1154
1273 ret = debuginfo__find_probe_location(dbg, pf);1155 ret = debuginfo__find_probe_location(dbg, pf);
1274 return ret;1156 return ret;
@@ -1677,44 +1559,6 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, · 402 unmodified lines
1677 return (ret < 0) ? ret : af.nvls;1559 return (ret < 0) ? ret : af.nvls;
1678}1560}
1679 1561
1680/* For the kernel module, we need a special code to get a DIE */
1681int 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
1718/* Reverse search */1562/* Reverse search */
1719int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,1563int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
1720 struct perf_probe_point *ppt)1564 struct perf_probe_point *ppt)
@@ -2009,41 +1853,6 @@ found: · 288 unmodified lines
2009 return (ret < 0) ? ret : lf.found;1853 return (ret < 0) ? ret : lf.found;
2010}1854}
2011 1855
2012#ifdef HAVE_DEBUGINFOD_SUPPORT
2013/* debuginfod doesn't require the comp_dir but buildid is required */
2014static 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
2040static 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
2047/*1856/*
2048 * Find a src file from a DWARF tag path. Prepend optional source path prefix1857 * Find a src file from a DWARF tag path. Prepend optional source path prefix
2049 * and chop off leading directories that do not exist. Result is passed back as1858 * 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
24#ifdef HAVE_DWARF_SUPPORT24#ifdef HAVE_DWARF_SUPPORT
25 25
26#include "dwarf-aux.h"26#include "dwarf-aux.h"
27 27#include "debuginfo.h"
28/* TODO: export debuginfo data structure even if no dwarf support */
29
30/* debug information structure */
31struct 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 */
40struct debuginfo *debuginfo__new(const char *path);
41void debuginfo__delete(struct debuginfo *dbg);
42 28
43/* Find probe_trace_events specified by perf_probe_event from debuginfo */29/* Find probe_trace_events specified by perf_probe_event from debuginfo */
44int debuginfo__find_trace_events(struct debuginfo *dbg,30int debuginfo__find_trace_events(struct debuginfo *dbg,
@@ -49,9 +35,6 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, · 4 unmodified lines
49int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,35int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
50 struct perf_probe_point *ppt);36 struct perf_probe_point *ppt);
51 37
52int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
53 bool adjust_offset);
54
55/* Find a line range */38/* Find a line range */
56int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr);39int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr);
57 40
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
237 237
238 evsel = evlist__last(temp_evlist);238 evsel = evlist__last(temp_evlist);
239 239
240 if (!evlist || perf_cpu_map__empty(evlist->core.user_requested_cpus)) {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(NULL);241 struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();
242 242
243 if (cpus)243 if (cpus)
244 cpu = perf_cpu_map__cpu(cpus, 0);244 cpu = perf_cpu_map__cpu(cpus, 0);
tools/perf/util/s390-cpumcf-kernel.h+2−0
@@ -12,6 +12,8 @@ · 11 unmodified lines
12#define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */12#define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */
13#define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */13#define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */
14#define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */14#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 */
15 17
16struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */18struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */
17 unsigned int def:16; /* 0-15 Data Entry Format */19 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
51 struct cf_trailer_entry *te;51 struct cf_trailer_entry *te;
52 struct cf_ctrset_entry *cep, ce;52 struct cf_ctrset_entry *cep, ce;
53 53
54 if (!len)
55 return false;
56 while (offset < len) {54 while (offset < len) {
57 cep = (struct cf_ctrset_entry *)(buf + offset);55 cep = (struct cf_ctrset_entry *)(buf + offset);
58 ce.def = be16_to_cpu(cep->def);56 ce.def = be16_to_cpu(cep->def);
@@ -125,6 +123,9 @@ static int get_counterset_start(int setnr) · 66 unmodified lines
125 return 128;123 return 128;
126 case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */124 case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */
127 return 448;125 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;
128 default:129 default:
129 return -1;130 return -1;
130 }131 }
@@ -212,27 +213,120 @@ static void s390_cpumcfdg_dump(struct perf_pmu *pmu, struct perf_sample *sample) · 81 unmodified lines
212 }213 }
213}214}
214 215
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 */
222struct 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 */
233static 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
242static 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
215/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events274/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events
216 * and if the event was triggered by a counter set diagnostic event display275 * and if the event was triggered by a
217 * its raw data.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.
218 * The function is only invoked when the dump flag -D is set.281 * 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.
219 */285 */
220void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)286void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event,
287 struct perf_sample *sample)
221{288{
289 const char *pai_name;
222 struct evsel *evsel;290 struct evsel *evsel;
223 291
224 if (event->header.type != PERF_RECORD_SAMPLE)292 if (event->header.type != PERF_RECORD_SAMPLE)
225 return;293 return;
226 294
227 evsel = evlist__event2evsel(evlist, event);295 evsel = evlist__event2evsel(evlist, event);
228 if (evsel == NULL ||296 if (!evsel)
229 evsel->core.attr.config != PERF_EVENT_CPUM_CF_DIAG)297 return;
298
299 /* Check for raw data in sample */
300 if (!sample->raw_size || !sample->raw_data)
230 return;301 return;
231 302
232 /* Display raw data on screen */303 /* Display raw data on screen */
233 if (!s390_cpumcfdg_testctr(sample)) {304 if (evsel->core.attr.config == PERF_EVENT_CPUM_CF_DIAG) {
234 pr_err("Invalid counter set data encountered\n");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:
235 return;322 return;
236 }323 }
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 }
238}332}
tools/perf/util/sample.h+1−0
@@ -113,6 +113,7 @@ struct perf_sample { · 112 unmodified lines
113 void *raw_data;113 void *raw_data;
114 struct ip_callchain *callchain;114 struct ip_callchain *callchain;
115 struct branch_stack *branch_stack;115 struct branch_stack *branch_stack;
116 u64 *branch_stack_cntr;
116 struct regs_dump user_regs;117 struct regs_dump user_regs;
117 struct regs_dump intr_regs;118 struct regs_dump intr_regs;
118 struct stack_dump user_stack;119 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
490 scripting_context->session = session;490 scripting_context->session = session;
491 491
492 command_line = malloc((argc + 2) * sizeof(const char *));492 command_line = malloc((argc + 2) * sizeof(const char *));
493 if (!command_line)
494 return -ENOMEM;
495
493 command_line[0] = "";496 command_line[0] = "";
494 command_line[1] = script;497 command_line[1] = script;
495 for (i = 2; i < argc + 2; i++)498 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
353 353
354 if (is_array) {354 if (is_array) {
355 list = PyList_New(field->arraylen);355 list = PyList_New(field->arraylen);
356 if (!list)
357 Py_FatalError("couldn't create Python list");
356 item_size = field->size / field->arraylen;358 item_size = field->size / field->arraylen;
357 n_items = field->arraylen;359 n_items = field->arraylen;
358 } else {360 } else {
@@ -754,7 +756,7 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, ch · 395 unmodified lines
754 }756 }
755}757}
756 758
757static void set_regs_in_dict(PyObject *dict,759static int set_regs_in_dict(PyObject *dict,
758 struct perf_sample *sample,760 struct perf_sample *sample,
759 struct evsel *evsel)761 struct evsel *evsel)
760{762{
@@ -770,6 +772,8 @@ static void set_regs_in_dict(PyObject *dict, · 9 unmodified lines
770 */772 */
771 int size = __sw_hweight64(attr->sample_regs_intr) * 28;773 int size = __sw_hweight64(attr->sample_regs_intr) * 28;
772 char *bf = malloc(size);774 char *bf = malloc(size);
775 if (!bf)
776 return -1;
773 777
774 regs_map(&sample->intr_regs, attr->sample_regs_intr, arch, bf, size);778 regs_map(&sample->intr_regs, attr->sample_regs_intr, arch, bf, size);
775 779
@@ -781,6 +785,8 @@ static void set_regs_in_dict(PyObject *dict, · 5 unmodified lines
781 pydict_set_item_string_decref(dict, "uregs",785 pydict_set_item_string_decref(dict, "uregs",
782 _PyUnicode_FromString(bf));786 _PyUnicode_FromString(bf));
783 free(bf);787 free(bf);
788
789 return 0;
784}790}
785 791
786static void set_sym_in_dict(PyObject *dict, struct addr_location *al,792static 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
920 PyLong_FromUnsignedLongLong(sample->cyc_cnt));926 PyLong_FromUnsignedLongLong(sample->cyc_cnt));
921 }927 }
922 928
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");
924 931
925 return dict;932 return dict;
926}933}
@@ -1918,12 +1925,18 @@ static int python_start_script(const char *script, int argc, const char **argv, · 991 unmodified lines
1918 scripting_context->session = session;1925 scripting_context->session = session;
1919#if PY_MAJOR_VERSION < 31926#if PY_MAJOR_VERSION < 3
1920 command_line = malloc((argc + 1) * sizeof(const char *));1927 command_line = malloc((argc + 1) * sizeof(const char *));
1928 if (!command_line)
1929 return -1;
1930
1921 command_line[0] = script;1931 command_line[0] = script;
1922 for (i = 1; i < argc + 1; i++)1932 for (i = 1; i < argc + 1; i++)
1923 command_line[i] = argv[i - 1];1933 command_line[i] = argv[i - 1];
1924 PyImport_AppendInittab(name, initperf_trace_context);1934 PyImport_AppendInittab(name, initperf_trace_context);
1925#else1935#else
1926 command_line = malloc((argc + 1) * sizeof(wchar_t *));1936 command_line = malloc((argc + 1) * sizeof(wchar_t *));
1937 if (!command_line)
1938 return -1;
1939
1927 command_line[0] = Py_DecodeLocale(script, NULL);1940 command_line[0] = Py_DecodeLocale(script, NULL);
1928 for (i = 1; i < argc + 1; i++)1941 for (i = 1; i < argc + 1; i++)
1929 command_line[i] = Py_DecodeLocale(argv[i - 1], NULL);1942 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
115 return -1;115 return -1;
116 }116 }
117 117
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
118 if (perf_data__is_pipe(data))123 if (perf_data__is_pipe(data))
119 return 0;124 return 0;
120 125
@@ -1150,9 +1155,13 @@ static void callchain__printf(struct evsel *evsel, · 1029 unmodified lines
1150 i, callchain->ips[i]);1155 i, callchain->ips[i]);
1151}1156}
1152 1157
1153static void branch_stack__printf(struct perf_sample *sample, bool callstack)1158static void branch_stack__printf(struct perf_sample *sample,
1159 struct evsel *evsel)
1154{1160{
1155 struct branch_entry *entries = perf_sample__branch_entries(sample);1161 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);
1156 uint64_t i;1165 uint64_t i;
1157 1166
1158 if (!callstack) {1167 if (!callstack) {
@@ -1194,6 +1203,13 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack) · 35 unmodified lines
1194 }1203 }
1195 }1204 }
1196 }1205 }
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 }
1197}1213}
1198 1214
1199static void regs_dump__printf(u64 mask, u64 *regs, const char *arch)1215static 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
1355 callchain__printf(evsel, sample);1371 callchain__printf(evsel, sample);
1356 1372
1357 if (evsel__has_br_stack(evsel))1373 if (evsel__has_br_stack(evsel))
1358 branch_stack__printf(sample, evsel__has_branch_callstack(evsel));1374 branch_stack__printf(sample, evsel);
1359 1375
1360 if (sample_type & PERF_SAMPLE_REGS_USER)1376 if (sample_type & PERF_SAMPLE_REGS_USER)
1361 regs_user__printf(sample, arch);1377 regs_user__printf(sample, arch);
tools/perf/util/sort.c+207−9
@@ -24,6 +24,7 @@ · 23 unmodified lines
24#include "strbuf.h"24#include "strbuf.h"
25#include "mem-events.h"25#include "mem-events.h"
26#include "annotate.h"26#include "annotate.h"
27#include "annotate-data.h"
27#include "event.h"28#include "event.h"
28#include "time-utils.h"29#include "time-utils.h"
29#include "cgroup.h"30#include "cgroup.h"
@@ -418,6 +419,52 @@ struct sort_entry sort_sym = { · 388 unmodified lines
418 .se_width_idx = HISTC_SYMBOL,419 .se_width_idx = HISTC_SYMBOL,
419};420};
420 421
422/* --sort symoff */
423
424static int64_t
425sort__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
436static int64_t
437sort__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
448static int
449hist_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
459struct 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
421/* --sort srcline */468/* --sort srcline */
422 469
423char *hist_entry__srcline(struct hist_entry *he)470char *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
583{630{
584 631
585 struct symbol *sym = he->ms.sym;632 struct symbol *sym = he->ms.sym;
586 struct annotation *notes;633 struct annotated_branch *branch;
587 double ipc = 0.0, coverage = 0.0;634 double ipc = 0.0, coverage = 0.0;
588 char tmp[64];635 char tmp[64];
589 636
590 if (!sym)637 if (!sym)
591 return repsep_snprintf(bf, size, "%-*s", width, "-");638 return repsep_snprintf(bf, size, "%-*s", width, "-");
592 639
593 notes = symbol__annotation(sym);640 branch = symbol__annotation(sym)->branch;
594 641
595 if (notes->hit_cycles)642 if (branch && branch->hit_cycles)
596 ipc = notes->hit_insn / ((double)notes->hit_cycles);643 ipc = branch->hit_insn / ((double)branch->hit_cycles);
597 644
598 if (notes->total_insn) {645 if (branch && branch->total_insn) {
599 coverage = notes->cover_insn * 100.0 /646 coverage = branch->cover_insn * 100.0 /
600 ((double)notes->total_insn);647 ((double)branch->total_insn);
601 }648 }
602 649
603 snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);650 snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);
@@ -2094,7 +2141,7 @@ struct sort_entry sort_dso_size = { · 1490 unmodified lines
2094 .se_width_idx = HISTC_DSO_SIZE,2141 .se_width_idx = HISTC_DSO_SIZE,
2095};2142};
2096 2143
2097/* --sort dso_size */2144/* --sort addr */
2098 2145
2099static int64_t2146static int64_t
2100sort__addr_cmp(struct hist_entry *left, struct hist_entry *right)2147sort__addr_cmp(struct hist_entry *left, struct hist_entry *right)
@@ -2131,6 +2178,152 @@ struct sort_entry sort_addr = { · 30 unmodified lines
2131 .se_width_idx = HISTC_ADDR,2178 .se_width_idx = HISTC_ADDR,
2132};2179};
2133 2180
2181/* --sort type */
2182
2183struct annotated_data_type unknown_type = {
2184 .self = {
2185 .type_name = (char *)"(unknown)",
2186 .children = LIST_HEAD_INIT(unknown_type.self.children),
2187 },
2188};
2189
2190static int64_t
2191sort__type_cmp(struct hist_entry *left, struct hist_entry *right)
2192{
2193 return sort__addr_cmp(left, right);
2194}
2195
2196static 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
2208static int64_t
2209sort__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
2227static int64_t
2228sort__type_sort(struct hist_entry *left, struct hist_entry *right)
2229{
2230 return sort__type_collapse(left, right);
2231}
2232
2233static 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
2239struct 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
2251static int64_t
2252sort__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
2274static 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
2299static 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
2317struct 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
2134 2327
2135struct sort_dimension {2328struct sort_dimension {
2136 const char *name;2329 const char *name;
@@ -2185,7 +2378,10 @@ static struct sort_dimension common_sort_dimensions[] = { · 48 unmodified lines
2185 DIM(SORT_ADDR, "addr", sort_addr),2378 DIM(SORT_ADDR, "addr", sort_addr),
2186 DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc),2379 DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc),
2187 DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc),2380 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),
2189};2385};
2190 2386
2191#undef DIM2387#undef DIM
@@ -3205,6 +3401,8 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, · 1013 unmodified lines
3205 list->thread = 1;3401 list->thread = 1;
3206 } else if (sd->entry == &sort_comm) {3402 } else if (sd->entry == &sort_comm) {
3207 list->comm = 1;3403 list->comm = 1;
3404 } else if (sd->entry == &sort_type_offset) {
3405 symbol_conf.annotate_data_member = true;
3208 }3406 }
3209 3407
3210 return __sort_dimension__add(sd, list, level);3408 return __sort_dimension__add(sd, list, level);
tools/perf/util/sort.h+7−0
@@ -15,6 +15,7 @@ · 14 unmodified lines
15 15
16struct option;16struct option;
17struct thread;17struct thread;
18struct annotated_data_type;
18 19
19extern regex_t parent_regex;20extern regex_t parent_regex;
20extern const char *sort_order;21extern const char *sort_order;
@@ -34,6 +35,7 @@ extern struct sort_entry sort_dso_to; · 13 unmodified lines
34extern struct sort_entry sort_sym_from;35extern struct sort_entry sort_sym_from;
35extern struct sort_entry sort_sym_to;36extern struct sort_entry sort_sym_to;
36extern struct sort_entry sort_srcline;37extern struct sort_entry sort_srcline;
38extern struct sort_entry sort_type;
37extern const char default_mem_sort_order[];39extern const char default_mem_sort_order[];
38extern bool chk_double_cl;40extern bool chk_double_cl;
39 41
@@ -111,6 +113,7 @@ struct hist_entry { · 71 unmodified lines
111 u64 p_stage_cyc;113 u64 p_stage_cyc;
112 u8 cpumode;114 u8 cpumode;
113 u8 depth;115 u8 depth;
116 int mem_type_off;
114 struct simd_flags simd_flags;117 struct simd_flags simd_flags;
115 118
116 /* We are added by hists__add_dummy_entry. */119 /* We are added by hists__add_dummy_entry. */
@@ -154,6 +157,7 @@ struct hist_entry { · 37 unmodified lines
154 struct perf_hpp_list *hpp_list;157 struct perf_hpp_list *hpp_list;
155 struct hist_entry *parent_he;158 struct hist_entry *parent_he;
156 struct hist_entry_ops *ops;159 struct hist_entry_ops *ops;
160 struct annotated_data_type *mem_type;
157 union {161 union {
158 /* this is for hierarchical entry structure */162 /* this is for hierarchical entry structure */
159 struct {163 struct {
@@ -243,6 +247,9 @@ enum sort_type { · 83 unmodified lines
243 SORT_LOCAL_RETIRE_LAT,247 SORT_LOCAL_RETIRE_LAT,
244 SORT_GLOBAL_RETIRE_LAT,248 SORT_GLOBAL_RETIRE_LAT,
245 SORT_SIMD,249 SORT_SIMD,
250 SORT_ANNOTATE_DATA_TYPE,
251 SORT_ANNOTATE_DATA_TYPE_OFFSET,
252 SORT_SYM_OFFSET,
246 253
247 /* branch stack specific sort keys */254 /* branch stack specific sort keys */
248 __SORT_BRANCH_STACK,255 __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
898 898
899static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter)899static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter)
900{900{
901 if (config->no_merge || hybrid_uniquify(counter, config))901 if (config->aggr_mode == AGGR_NONE || hybrid_uniquify(counter, config))
902 uniquify_event_name(counter);902 uniquify_event_name(counter);
903}903}
904 904
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
264 static const double color_ratios[3] = {20.0, 10.0, 5.0};264 static const double color_ratios[3] = {20.0, 10.0, 5.0};
265 265
266 print_ratio(config, evsel, aggr_idx, misses, out, STAT_LL_CACHE, color_ratios,266 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");
268}268}
269 269
270static void print_dtlb_miss(struct perf_stat_config *config,270static 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
315 if (!counter->per_pkg)315 if (!counter->per_pkg)
316 return 0;316 return 0;
317 317
318 if (perf_cpu_map__empty(cpus))318 if (perf_cpu_map__has_any_cpu_or_is_empty(cpus))
319 return 0;319 return 0;
320 320
321 if (!mask) {321 if (!mask) {
@@ -592,7 +592,7 @@ void perf_stat_merge_counters(struct perf_stat_config *config, struct evlist *ev · 270 unmodified lines
592{592{
593 struct evsel *evsel;593 struct evsel *evsel;
594 594
595 if (config->no_merge)595 if (config->aggr_mode == AGGR_NONE)
596 return;596 return;
597 597
598 evlist__for_each_entry(evlist, evsel)598 evlist__for_each_entry(evlist, evsel)
tools/perf/util/stat.h+0−1
@@ -76,7 +76,6 @@ struct perf_stat_config { · 75 unmodified lines
76 bool null_run;76 bool null_run;
77 bool ru_display;77 bool ru_display;
78 bool big_num;78 bool big_num;
79 bool no_merge;
80 bool hybrid_merge;79 bool hybrid_merge;
81 bool walltime_run_table;80 bool walltime_run_table;
82 bool all_kernel;81 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
1392 map__set_start(map, shdr->sh_addr + ref_reloc(kmap));1392 map__set_start(map, shdr->sh_addr + ref_reloc(kmap));
1393 map__set_end(map, map__start(map) + shdr->sh_size);1393 map__set_end(map, map__start(map) + shdr->sh_size);
1394 map__set_pgoff(map, shdr->sh_offset);1394 map__set_pgoff(map, shdr->sh_offset);
1395 map__set_map_ip(map, map__dso_map_ip);1395 map__set_mapping_type(map, MAPPING_TYPE__DSO);
1396 map__set_unmap_ip(map, map__dso_unmap_ip);
1397 /* Ensure maps are correctly ordered */1396 /* Ensure maps are correctly ordered */
1398 if (kmaps) {1397 if (kmaps) {
1399 int err;1398 int err;
@@ -1455,8 +1454,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, · 55 unmodified lines
1455 map__set_end(curr_map, map__start(curr_map) + shdr->sh_size);1454 map__set_end(curr_map, map__start(curr_map) + shdr->sh_size);
1456 map__set_pgoff(curr_map, shdr->sh_offset);1455 map__set_pgoff(curr_map, shdr->sh_offset);
1457 } else {1456 } else {
1458 map__set_map_ip(curr_map, identity__map_ip);1457 map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY);
1459 map__set_unmap_ip(curr_map, identity__map_ip);
1460 }1458 }
1461 curr_dso->symtab_type = dso->symtab_type;1459 curr_dso->symtab_type = dso->symtab_type;
1462 if (maps__insert(kmaps, curr_map))1460 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
159 goto out_free;159 goto out_free;
160 160
161 ret = read_build_id(buf, buf_size, bid, need_swap);161 ret = read_build_id(buf, buf_size, bid, need_swap);
162 if (ret == 0)162 if (ret == 0) {
163 ret = bid->size;163 ret = bid->size;
164 break;164 break;
165 }
165 }166 }
166 } else {167 } else {
167 Elf64_Ehdr ehdr;168 Elf64_Ehdr ehdr;
@@ -210,9 +211,10 @@ int filename__read_build_id(const char *filename, struct build_id *bid) · 42 unmodified lines
210 goto out_free;211 goto out_free;
211 212
212 ret = read_build_id(buf, buf_size, bid, need_swap);213 ret = read_build_id(buf, buf_size, bid, need_swap);
213 if (ret == 0)214 if (ret == 0) {
214 ret = bid->size;215 ret = bid->size;
215 break;216 break;
217 }
216 }218 }
217 }219 }
218out_free:220out_free:
tools/perf/util/symbol.c+29−277
@@ -48,11 +48,6 @@ static bool symbol__is_idle(const char *name); · 47 unmodified lines
48int vmlinux_path__nr_entries;48int vmlinux_path__nr_entries;
49char **vmlinux_path;49char **vmlinux_path;
50 50
51struct map_list_node {
52 struct list_head node;
53 struct map *map;
54};
55
56struct symbol_conf symbol_conf = {51struct symbol_conf symbol_conf = {
57 .nanosecs = false,52 .nanosecs = false,
58 .use_modules = true,53 .use_modules = true,
@@ -90,11 +85,6 @@ static enum dso_binary_type binary_type_symtab[] = { · 31 unmodified lines
90 85
91#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)86#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
92 87
93static struct map_list_node *map_list_node__new(void)
94{
95 return malloc(sizeof(struct map_list_node));
96}
97
98static bool symbol_type__filter(char symbol_type)88static bool symbol_type__filter(char symbol_type)
99{89{
100 symbol_type = toupper(symbol_type);90 symbol_type = toupper(symbol_type);
@@ -270,29 +260,6 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) · 169 unmodified lines
270 curr->end = roundup(curr->start, 4096) + 4096;260 curr->end = roundup(curr->start, 4096) + 4096;
271}261}
272 262
273void 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
296struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)263struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
297{264{
298 size_t namelen = strlen(name) + 1;265 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
956 return -1;923 return -1;
957 }924 }
958 925
959 map__set_map_ip(curr_map, identity__map_ip);926 map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY);
960 map__set_unmap_ip(curr_map, identity__map_ip);
961 if (maps__insert(kmaps, curr_map)) {927 if (maps__insert(kmaps, curr_map)) {
962 dso__put(ndso);928 dso__put(ndso);
963 return -1;929 return -1;
@@ -1148,33 +1114,35 @@ out_delete_from: · 184 unmodified lines
1148 return ret;1114 return ret;
1149}1115}
1150 1116
1117static 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
1151static int do_validate_kcore_modules(const char *filename, struct maps *kmaps)1135static int do_validate_kcore_modules(const char *filename, struct maps *kmaps)
1152{1136{
1153 struct rb_root modules = RB_ROOT;1137 struct rb_root modules = RB_ROOT;
1154 struct map_rb_node *old_node;
1155 int err;1138 int err;
1156 1139
1157 err = read_proc_modules(filename, &modules);1140 err = read_proc_modules(filename, &modules);
1158 if (err)1141 if (err)
1159 return err;1142 return err;
1160 1143
1161 maps__for_each_entry(kmaps, old_node) {1144 err = maps__for_each_map(kmaps, do_validate_kcore_modules_cb, &modules);
1162 struct map *old_map = old_node->map;
1163 struct module_info *mi;
1164 struct dso *dso;
1165 1145
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 }
1177out:
1178 delete_modules(&modules);1146 delete_modules(&modules);
1179 return err;1147 return err;
1180}1148}
@@ -1271,101 +1239,15 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) · 90 unmodified lines
1271 return 0;1239 return 0;
1272}1240}
1273 1241
1274/*1242static bool remove_old_maps(struct map *map, void *data)
1275 * Merges map into maps by splitting the new map within the existing map
1276 * regions.
1277 */
1278int maps__merge_in(struct maps *kmaps, struct map *new_map)
1279{1243{
1280 struct map_rb_node *rb_node;1244 const struct map *map_to_save = data;
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
1351out:
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 }
1362 1245
1363 if (new_map) {1246 /*
1364 if (!err)1247 * We need to preserve eBPF maps even if they are covered by kcore,
1365 err = maps__insert(kmaps, new_map);1248 * because we need to access eBPF dso for source data.
1366 map__put(new_map);1249 */
1367 }1250 return !RC_CHK_EQUAL(map, map_to_save) && !__map__is_bpf_prog(map);
1368 return err;
1369}1251}
1370 1252
1371static int dso__load_kcore(struct dso *dso, struct map *map,1253static 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
1374 struct maps *kmaps = map__kmaps(map);1256 struct maps *kmaps = map__kmaps(map);
1375 struct kcore_mapfn_data md;1257 struct kcore_mapfn_data md;
1376 struct map *replacement_map = NULL;1258 struct map *replacement_map = NULL;
1377 struct map_rb_node *old_node, *next;
1378 struct machine *machine;1259 struct machine *machine;
1379 bool is_64_bit;1260 bool is_64_bit;
1380 int err, fd;1261 int err, fd;
@@ -1421,17 +1302,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, · 40 unmodified lines
1421 }1302 }
1422 1303
1423 /* Remove old maps */1304 /* Remove old maps */
1424 maps__for_each_entry_safe(kmaps, old_node, next) {1305 maps__remove_maps(kmaps, remove_old_maps, map);
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 }
1435 machine->trampolines_mapped = false;1306 machine->trampolines_mapped = false;
1436 1307
1437 /* Find the kernel map using the '_stext' symbol */1308 /* 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
1475 map__set_start(map, map__start(new_map));1346 map__set_start(map, map__start(new_map));
1476 map__set_end(map, map__end(new_map));1347 map__set_end(map, map__end(new_map));
1477 map__set_pgoff(map, map__pgoff(new_map));1348 map__set_pgoff(map, map__pgoff(new_map));
1478 map__set_map_ip(map, map__map_ip_ptr(new_map));1349 map__set_mapping_type(map, map__mapping_type(new_map));
1479 map__set_unmap_ip(map, map__unmap_ip_ptr(new_map));
1480 /* Ensure maps are correctly ordered */1350 /* Ensure maps are correctly ordered */
1481 map_ref = map__get(map);1351 map_ref = map__get(map);
1482 maps__remove(kmaps, map_ref);1352 maps__remove(kmaps, map_ref);
@@ -2067,124 +1937,6 @@ out: · 584 unmodified lines
2067 return ret;1937 return ret;
2068}1938}
2069 1939
2070static 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
2091static 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
2098void __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
2103static 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
2130static 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
2145struct 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
2183out_unlock:
2184 up_read(maps__lock(maps));
2185 return map;
2186}
2187
2188int dso__load_vmlinux(struct dso *dso, struct map *map,1940int dso__load_vmlinux(struct dso *dso, struct map *map,
2189 const char *vmlinux, bool vmlinux_allocated)1941 const char *vmlinux, bool vmlinux_allocated)
2190{1942{
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
189void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym);189void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym);
190void symbols__fixup_duplicate(struct rb_root_cached *symbols);190void symbols__fixup_duplicate(struct rb_root_cached *symbols);
191void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms);191void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms);
192void maps__fixup_end(struct maps *maps);
193 192
194typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);193typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
195int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,194int 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
42 inline_name,42 inline_name,
43 disable_add2line_warn,43 disable_add2line_warn,
44 buildid_mmap2,44 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;
46 const char *vmlinux_name,50 const char *vmlinux_name,
47 *kallsyms_name,51 *kallsyms_name,
48 *source_prefix,52 *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
665}665}
666#endif666#endif
667 667
668struct 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
675static 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
668int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process,720int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process,
669 struct machine *machine)721 struct machine *machine)
670{722{
671 int rc = 0;723 int rc;
672 struct map_rb_node *pos;
673 struct maps *maps = machine__kernel_maps(machine);724 struct maps *maps = machine__kernel_maps(machine);
674 union perf_event *event;725 struct perf_event__synthesize_modules_maps_cb_args args = {
675 size_t size = symbol_conf.buildid_mmap2 ?726 .tool = tool,
676 sizeof(event->mmap2) : sizeof(event->mmap);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);
677 733
678 event = zalloc(size + machine->id_hdr_size);734 args.event = zalloc(size + machine->id_hdr_size);
679 if (event == NULL) {735 if (args.event == NULL) {
680 pr_debug("Not enough memory synthesizing mmap event "736 pr_debug("Not enough memory synthesizing mmap event "
681 "for kernel modules\n");737 "for kernel modules\n");
682 return -1;738 return -1;
@@ -687,53 +743,13 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t · 4 unmodified lines
687 * __perf_event_mmap743 * __perf_event_mmap
688 */744 */
689 if (machine__is_host(machine))745 if (machine__is_host(machine))
690 event->header.misc = PERF_RECORD_MISC_KERNEL;746 args.event->header.misc = PERF_RECORD_MISC_KERNEL;
691 else747 else
692 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;748 args.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;
697 749
698 if (!__map__is_kmodule(map))750 rc = maps__for_each_map(maps, perf_event__synthesize_modules_maps_cb, &args);
699 continue;
700 751
701 dso = map__dso(map);752 free(args.event);
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);
737 return rc;753 return rc;
738}754}
739 755
tools/perf/util/thread.c+20−22
@@ -345,38 +345,36 @@ int thread__insert_map(struct thread *thread, struct map *map) · 344 unmodified lines
345 if (ret)345 if (ret)
346 return ret;346 return ret;
347 347
348 maps__fixup_overlappings(thread__maps(thread), map, stderr);348 return maps__fixup_overlap_and_insert(thread__maps(thread), map);
349 return maps__insert(thread__maps(thread), map);
350}349}
351 350
352static int __thread__prepare_access(struct thread *thread)351struct thread__prepare_access_maps_cb_args {
352 int err;
353 struct maps *maps;
354};
355
356static int thread__prepare_access_maps_cb(struct map *map, void *data)
353{357{
354 bool initialized = false;358 bool initialized = false;
355 int err = 0;359 struct thread__prepare_access_maps_cb_args *args = data;
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 }
366 360
367 up_read(maps__lock(maps));361 args->err = unwind__prepare_access(args->maps, map, &initialized);
368 362
369 return err;363 return (args->err || initialized) ? 1 : 0;
370}364}
371 365
372static int thread__prepare_access(struct thread *thread)366static int thread__prepare_access(struct thread *thread)
373{367{
374 int err = 0;368 struct thread__prepare_access_maps_cb_args args = {
369 .err = 0,
370 };
375 371
376 if (dwarf_callchain_users)372 if (dwarf_callchain_users) {
377 err = __thread__prepare_access(thread);373 args.maps = thread__maps(thread);
374 maps__for_each_map(thread__maps(thread), thread__prepare_access_maps_cb, &args);
375 }
378 376
379 return err;377 return args.err;
380}378}
381 379
382static int thread__clone_maps(struct thread *thread, struct thread *parent, bool do_maps_clone)380static 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
385 if (thread__pid(thread) == thread__pid(parent))383 if (thread__pid(thread) == thread__pid(parent))
386 return thread__prepare_access(thread);384 return thread__prepare_access(thread);
387 385
388 if (thread__maps(thread) == thread__maps(parent)) {386 if (RC_CHK_EQUAL(thread__maps(thread), thread__maps(parent))) {
389 pr_debug("broken map groups on thread %d/%d parent %d/%d\n",387 pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
390 thread__pid(thread), thread__tid(thread),388 thread__pid(thread), thread__tid(thread),
391 thread__pid(parent), thread__tid(parent));389 thread__pid(parent), thread__tid(parent));
392 return 0;390 return 0;
393 }391 }
394 /* But this one is new process, copy maps. */392 /* 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;
396}394}
397 395
398int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone)396int 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
36};36};
37 37
38DECLARE_RC_STRUCT(thread) {38DECLARE_RC_STRUCT(thread) {
39 /** @maps: mmaps associated with this thread. */
39 struct maps *maps;40 struct maps *maps;
40 pid_t pid_; /* Not all tools update this */41 pid_t pid_; /* Not all tools update this */
42 /** @tid: thread ID number unique to a machine. */
41 pid_t tid;43 pid_t tid;
44 /** @ppid: parent process of the process this thread belongs to. */
42 pid_t ppid;45 pid_t ppid;
43 int cpu;46 int cpu;
44 int guest_cpu; /* For QEMU thread */47 int guest_cpu; /* For QEMU thread */
45 refcount_t refcnt;48 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;
46 bool comm_set;55 bool comm_set;
47 int comm_len;56 int comm_len;
48 struct list_head namespaces_list;57 struct list_head namespaces_list;
@@ -189,6 +198,11 @@ static inline refcount_t *thread__refcnt(struct thread *thread) · 140 unmodified lines
189 return &RC_CHK_ACCESS(thread)->refcnt;198 return &RC_CHK_ACCESS(thread)->refcnt;
190}199}
191 200
201static inline void thread__set_exited(struct thread *thread, bool exited)
202{
203 RC_CHK_ACCESS(thread)->exited = exited;
204}
205
192static inline bool thread__comm_set(const struct thread *thread)206static inline bool thread__comm_set(const struct thread *thread)
193{207{
194 return RC_CHK_ACCESS(thread)->comm_set;208 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
28 struct record_opts *opts = &top->record_opts;28 struct record_opts *opts = &top->record_opts;
29 struct target *target = &opts->target;29 struct target *target = &opts->target;
30 size_t ret = 0;30 size_t ret = 0;
31 int nr_cpus;
31 32
32 if (top->samples) {33 if (top->samples) {
33 samples_per_sec = top->samples / top->delay_secs;34 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
93 else94 else
94 ret += SNPRINTF(bf + ret, size - ret, " (all");95 ret += SNPRINTF(bf + ret, size - ret, " (all");
95 96
97 nr_cpus = perf_cpu_map__nr(top->evlist->core.user_requested_cpus);
96 if (target->cpu_list)98 if (target->cpu_list)
97 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",99 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
98 perf_cpu_map__nr(top->evlist->core.user_requested_cpus) > 1100 nr_cpus > 1 ? "s" : "",
99 ? "s" : "",
100 target->cpu_list);101 target->cpu_list);
101 else {102 else {
102 if (target->tid)103 if (target->tid)
103 ret += SNPRINTF(bf + ret, size - ret, ")");104 ret += SNPRINTF(bf + ret, size - ret, ")");
104 else105 else
105 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",106 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
106 perf_cpu_map__nr(top->evlist->core.user_requested_cpus),107 nr_cpus, nr_cpus > 1 ? "s" : "");
107 perf_cpu_map__nr(top->evlist->core.user_requested_cpus) > 1
108 ? "s" : "");
109 }108 }
110 109
111 perf_top__reset_sample_counters(top);110 perf_top__reset_sample_counters(top);
tools/perf/util/top.h+0−1
@@ -21,7 +21,6 @@ struct perf_top { · 20 unmodified lines
21 struct perf_tool tool;21 struct perf_tool tool;
22 struct evlist *evlist, *sb_evlist;22 struct evlist *evlist, *sb_evlist;
23 struct record_opts record_opts;23 struct record_opts record_opts;
24 struct annotation_options annotation_opts;
25 struct evswitch evswitch;24 struct evswitch evswitch;
26 /*25 /*
27 * Symbols will be added here in perf_event__process_sample and will26 * 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
46{46{
47 Dwfl_Module *mod;47 Dwfl_Module *mod;
48 struct dso *dso = NULL;48 struct dso *dso = NULL;
49 Dwarf_Addr base;
49 /*50 /*
50 * Some callers will use al->sym, so we can't just use the51 * Some callers will use al->sym, so we can't just use the
51 * cheaper thread__find_map() here.52 * cheaper thread__find_map() here.
@@ -58,13 +59,25 @@ static int __report_module(struct addr_location *al, u64 ip, · 6 unmodified lines
58 if (!dso)59 if (!dso)
59 return 0;60 return 0;
60 61
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
61 mod = dwfl_addrmodule(ui->dwfl, ip);74 mod = dwfl_addrmodule(ui->dwfl, ip);
62 if (mod) {75 if (mod) {
63 Dwarf_Addr s;76 Dwarf_Addr s;
64 77
65 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);78 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
66 if (s != map__start(al->map) - map__pgoff(al->map))79 if (s != base)
67 mod = 0;80 mod = NULL;
68 }81 }
69 82
70 if (!mod) {83 if (!mod) {
@@ -72,14 +85,14 @@ static int __report_module(struct addr_location *al, u64 ip, · 1 unmodified line
72 85
73 __symbol__join_symfs(filename, sizeof(filename), dso->long_name);86 __symbol__join_symfs(filename, sizeof(filename), dso->long_name);
74 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,87 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
75 map__start(al->map) - map__pgoff(al->map), false);88 base, false);
76 }89 }
77 if (!mod) {90 if (!mod) {
78 char filename[PATH_MAX];91 char filename[PATH_MAX];
79 92
80 if (dso__build_id_filename(dso, filename, sizeof(filename), false))93 if (dso__build_id_filename(dso, filename, sizeof(filename), false))
81 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,94 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
82 map__start(al->map) - map__pgoff(al->map), false);95 base, false);
83 }96 }
84 97
85 if (mod) {98 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
302 return 0;302 return 0;
303}303}
304 304
305struct read_unwind_spec_eh_frame_maps_cb_args {
306 struct dso *dso;
307 u64 base_addr;
308};
309
310static 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
305static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui,322static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui,
306 u64 *table_data, u64 *segbase,323 u64 *table_data, u64 *segbase,
307 u64 *fde_count)324 u64 *fde_count)
308{325{
309 struct map_rb_node *map_node;326 struct read_unwind_spec_eh_frame_maps_cb_args args = {
310 u64 base_addr = UINT64_MAX;327 .dso = dso,
328 .base_addr = UINT64_MAX,
329 };
311 int ret, fd;330 int ret, fd;
312 331
313 if (dso->data.eh_frame_hdr_offset == 0) {332 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
325 return -EINVAL;344 return -EINVAL;
326 }345 }
327 346
328 maps__for_each_entry(thread__maps(ui->thread), map_node) {347 maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_maps_cb, &args);
329 struct map *map = map_node->map;
330 u64 start = map__start(map);
331 348
332 if (map__dso(map) == dso && start < base_addr)349 args.base_addr -= dso->data.elf_base_addr;
333 base_addr = start;
334 }
335 base_addr -= dso->data.elf_base_addr;
336 /* Address of .eh_frame_hdr */350 /* 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;
338 ret = unwind_spec_ehframe(dso, ui->machine, dso->data.eh_frame_hdr_offset,352 ret = unwind_spec_ehframe(dso, ui->machine, dso->data.eh_frame_hdr_offset,
339 table_data, fde_count);353 table_data, fde_count);
340 if (ret)354 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
140 return dso;140 return dso;
141}141}
142 142
143struct machine__thread_dso_type_maps_cb_args {
144 struct machine *machine;
145 enum dso_type dso_type;
146};
147
148static 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
143static enum dso_type machine__thread_dso_type(struct machine *machine,160static enum dso_type machine__thread_dso_type(struct machine *machine,
144 struct thread *thread)161 struct thread *thread)
145{162{
146 enum dso_type dso_type = DSO__TYPE_UNKNOWN;163 struct machine__thread_dso_type_maps_cb_args args = {
147 struct map_rb_node *rb_node;164 .machine = machine,
148 165 .dso_type = DSO__TYPE_UNKNOWN,
149 maps__for_each_entry(thread__maps(thread), rb_node) {166 };
150 struct dso *dso = map__dso(rb_node->map);
151 167
152 if (!dso || dso->long_name[0] != '/')168 maps__for_each_map(thread__maps(thread), machine__thread_dso_type_maps_cb, &args);
153 continue;
154 dso_type = dso__type(dso, machine);
155 if (dso_type != DSO__TYPE_UNKNOWN)
156 break;
157 }
158 169
159 return dso_type;170 return args.dso_type;
160}171}
161 172
162#if BITS_PER_LONG == 64173#if BITS_PER_LONG == 64
tools/perf/util/zstd.c+33−30
@@ -7,35 +7,9 @@ · 6 unmodified lines
7 7
8int zstd_init(struct zstd_data *data, int level)8int zstd_init(struct zstd_data *data, int level)
9{9{
10 size_t ret;10 data->comp_level = level;
11 11 data->dstream = NULL;
12 data->dstream = ZSTD_createDStream();12 data->cstream = NULL;
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
39 return 0;13 return 0;
40}14}
41 15
@@ -54,7 +28,7 @@ int zstd_fini(struct zstd_data *data) · 12 unmodified lines
54 return 0;28 return 0;
55}29}
56 30
57size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,31ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,
58 void *src, size_t src_size, size_t max_record_size,32 void *src, size_t src_size, size_t max_record_size,
59 size_t process_header(void *record, size_t increment))33 size_t process_header(void *record, size_t increment))
60{34{
@@ -63,6 +37,21 @@ size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t · 2 unmodified lines
63 ZSTD_outBuffer output;37 ZSTD_outBuffer output;
64 void *record;38 void *record;
65 39
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
66 while (input.pos < input.size) {55 while (input.pos < input.size) {
67 record = dst;56 record = dst;
68 size = process_header(record, 0);57 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
96 ZSTD_inBuffer input = { src, src_size, 0 };85 ZSTD_inBuffer input = { src, src_size, 0 };
97 ZSTD_outBuffer output = { dst, dst_size, 0 };86 ZSTD_outBuffer output = { dst, dst_size, 0 };
98 87
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 }
99 while (input.pos < input.size) {102 while (input.pos < input.size) {
100 ret = ZSTD_decompressStream(data->dstream, &output, &input);103 ret = ZSTD_decompressStream(data->dstream, &output, &input);
101 if (ZSTD_isError(ret)) {104 if (ZSTD_isError(ret)) {