summaryrefslogtreecommitdiff
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/Build394
-rw-r--r--tools/perf/util/arm-spe-decoder/Build2
-rw-r--r--tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c23
-rw-r--r--tools/perf/util/bpf-filter.c33
-rw-r--r--tools/perf/util/bpf-filter.h5
-rw-r--r--tools/perf/util/bpf-filter.l66
-rw-r--r--tools/perf/util/bpf-filter.y7
-rw-r--r--tools/perf/util/bpf_skel/sample-filter.h40
-rw-r--r--tools/perf/util/bpf_skel/sample_filter.bpf.c73
-rw-r--r--tools/perf/util/comm.c29
-rw-r--r--tools/perf/util/cs-etm-decoder/Build2
-rw-r--r--tools/perf/util/cs-etm.c10
-rw-r--r--tools/perf/util/disasm.c10
-rw-r--r--tools/perf/util/dso.c12
-rw-r--r--tools/perf/util/dso.h14
-rw-r--r--tools/perf/util/dsos.c31
-rw-r--r--tools/perf/util/events_stats.h3
-rw-r--r--tools/perf/util/evsel.c239
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/expr.c4
-rw-r--r--tools/perf/util/genelf.c5
-rw-r--r--tools/perf/util/hisi-ptt-decoder/Build2
-rw-r--r--tools/perf/util/hisi-ptt.c5
-rw-r--r--tools/perf/util/hist.c6
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/intel-pt-decoder/Build2
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c9
-rw-r--r--tools/perf/util/maps.c113
-rw-r--r--tools/perf/util/mem-events.c16
-rw-r--r--tools/perf/util/parse-events.c10
-rw-r--r--tools/perf/util/perf-regs-arch/Build18
-rw-r--r--tools/perf/util/pmu.c54
-rw-r--r--tools/perf/util/pmus.c72
-rw-r--r--tools/perf/util/pmus.h7
-rw-r--r--tools/perf/util/python-ext-sources53
-rw-r--r--tools/perf/util/python.c271
-rw-r--r--tools/perf/util/scripting-engines/Build4
-rw-r--r--tools/perf/util/session.c25
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/setup.py33
-rw-r--r--tools/perf/util/sort.c2
-rw-r--r--tools/perf/util/srcline.c14
-rw-r--r--tools/perf/util/stat-display.c20
-rw-r--r--tools/perf/util/stat-shadow.c7
-rw-r--r--tools/perf/util/symbol.c23
-rw-r--r--tools/perf/util/symbol_conf.h3
-rw-r--r--tools/perf/util/syscalltbl.c7
-rw-r--r--tools/perf/util/syscalltbl.h1
-rw-r--r--tools/perf/util/unwind-libdw.c12
-rw-r--r--tools/perf/util/unwind-libunwind-local.c23
50 files changed, 1109 insertions, 725 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index da64efd8718f..0f18fe81ef0b 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -1,181 +1,181 @@
include $(srctree)/tools/scripts/Makefile.include
include $(srctree)/tools/scripts/utilities.mak
-perf-y += arm64-frame-pointer-unwind-support.o
-perf-y += addr_location.o
-perf-y += annotate.o
-perf-y += block-info.o
-perf-y += block-range.o
-perf-y += build-id.o
-perf-y += cacheline.o
-perf-y += config.o
-perf-y += copyfile.o
-perf-y += ctype.o
-perf-y += db-export.o
-perf-y += disasm.o
-perf-y += env.o
-perf-y += event.o
-perf-y += evlist.o
-perf-y += sideband_evlist.o
-perf-y += evsel.o
-perf-y += evsel_fprintf.o
-perf-y += perf_event_attr_fprintf.o
-perf-y += evswitch.o
-perf-y += find_bit.o
-perf-y += get_current_dir_name.o
-perf-y += levenshtein.o
-perf-y += mmap.o
-perf-y += memswap.o
-perf-y += parse-events.o
-perf-y += print-events.o
-perf-y += tracepoint.o
-perf-y += perf_regs.o
-perf-y += perf-regs-arch/
-perf-y += path.o
-perf-y += print_binary.o
-perf-y += print_insn.o
-perf-y += rlimit.o
-perf-y += argv_split.o
-perf-y += rbtree.o
-perf-y += libstring.o
-perf-y += bitmap.o
-perf-y += hweight.o
-perf-y += smt.o
-perf-y += strbuf.o
-perf-y += string.o
-perf-y += strlist.o
-perf-y += strfilter.o
-perf-y += top.o
-perf-y += usage.o
-perf-y += dso.o
-perf-y += dsos.o
-perf-y += symbol.o
-perf-y += symbol_fprintf.o
-perf-y += map_symbol.o
-perf-y += color.o
-perf-y += color_config.o
-perf-y += metricgroup.o
-perf-y += header.o
-perf-y += callchain.o
-perf-y += values.o
-perf-y += debug.o
-perf-y += fncache.o
-perf-y += machine.o
-perf-y += map.o
-perf-y += maps.o
-perf-y += pstack.o
-perf-y += session.o
-perf-y += sample-raw.o
-perf-y += s390-sample-raw.o
-perf-y += amd-sample-raw.o
-perf-$(CONFIG_TRACE) += syscalltbl.o
-perf-y += ordered-events.o
-perf-y += namespaces.o
-perf-y += comm.o
-perf-y += thread.o
-perf-y += threads.o
-perf-y += thread_map.o
-perf-y += parse-events-flex.o
-perf-y += parse-events-bison.o
-perf-y += pmu.o
-perf-y += pmus.o
-perf-y += pmu-flex.o
-perf-y += pmu-bison.o
-perf-y += svghelper.o
-perf-$(CONFIG_LIBTRACEEVENT) += trace-event-info.o
-perf-y += trace-event-scripting.o
-perf-$(CONFIG_LIBTRACEEVENT) += trace-event.o
-perf-$(CONFIG_LIBTRACEEVENT) += trace-event-parse.o
-perf-$(CONFIG_LIBTRACEEVENT) += trace-event-read.o
-perf-y += sort.o
-perf-y += hist.o
-perf-y += util.o
-perf-y += cpumap.o
-perf-y += affinity.o
-perf-y += cputopo.o
-perf-y += cgroup.o
-perf-y += target.o
-perf-y += rblist.o
-perf-y += intlist.o
-perf-y += vdso.o
-perf-y += counts.o
-perf-y += stat.o
-perf-y += stat-shadow.o
-perf-y += stat-display.o
-perf-y += perf_api_probe.o
-perf-y += record.o
-perf-y += srcline.o
-perf-y += srccode.o
-perf-y += synthetic-events.o
-perf-y += data.o
-perf-y += tsc.o
-perf-y += cloexec.o
-perf-y += call-path.o
-perf-y += rwsem.o
-perf-y += thread-stack.o
-perf-y += spark.o
-perf-y += topdown.o
-perf-y += iostat.o
-perf-y += stream.o
-perf-$(CONFIG_AUXTRACE) += auxtrace.o
-perf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
-perf-$(CONFIG_AUXTRACE) += intel-pt.o
-perf-$(CONFIG_AUXTRACE) += intel-bts.o
-perf-$(CONFIG_AUXTRACE) += arm-spe.o
-perf-$(CONFIG_AUXTRACE) += arm-spe-decoder/
-perf-$(CONFIG_AUXTRACE) += hisi-ptt.o
-perf-$(CONFIG_AUXTRACE) += hisi-ptt-decoder/
-perf-$(CONFIG_AUXTRACE) += s390-cpumsf.o
+perf-util-y += arm64-frame-pointer-unwind-support.o
+perf-util-y += addr_location.o
+perf-util-y += annotate.o
+perf-util-y += block-info.o
+perf-util-y += block-range.o
+perf-util-y += build-id.o
+perf-util-y += cacheline.o
+perf-util-y += config.o
+perf-util-y += copyfile.o
+perf-util-y += ctype.o
+perf-util-y += db-export.o
+perf-util-y += disasm.o
+perf-util-y += env.o
+perf-util-y += event.o
+perf-util-y += evlist.o
+perf-util-y += sideband_evlist.o
+perf-util-y += evsel.o
+perf-util-y += evsel_fprintf.o
+perf-util-y += perf_event_attr_fprintf.o
+perf-util-y += evswitch.o
+perf-util-y += find_bit.o
+perf-util-y += get_current_dir_name.o
+perf-util-y += levenshtein.o
+perf-util-y += mmap.o
+perf-util-y += memswap.o
+perf-util-y += parse-events.o
+perf-util-y += print-events.o
+perf-util-y += tracepoint.o
+perf-util-y += perf_regs.o
+perf-util-y += perf-regs-arch/
+perf-util-y += path.o
+perf-util-y += print_binary.o
+perf-util-y += print_insn.o
+perf-util-y += rlimit.o
+perf-util-y += argv_split.o
+perf-util-y += rbtree.o
+perf-util-y += libstring.o
+perf-util-y += bitmap.o
+perf-util-y += hweight.o
+perf-util-y += smt.o
+perf-util-y += strbuf.o
+perf-util-y += string.o
+perf-util-y += strlist.o
+perf-util-y += strfilter.o
+perf-util-y += top.o
+perf-util-y += usage.o
+perf-util-y += dso.o
+perf-util-y += dsos.o
+perf-util-y += symbol.o
+perf-util-y += symbol_fprintf.o
+perf-util-y += map_symbol.o
+perf-util-y += color.o
+perf-util-y += color_config.o
+perf-util-y += metricgroup.o
+perf-util-y += header.o
+perf-util-y += callchain.o
+perf-util-y += values.o
+perf-util-y += debug.o
+perf-util-y += fncache.o
+perf-util-y += machine.o
+perf-util-y += map.o
+perf-util-y += maps.o
+perf-util-y += pstack.o
+perf-util-y += session.o
+perf-util-y += sample-raw.o
+perf-util-y += s390-sample-raw.o
+perf-util-y += amd-sample-raw.o
+perf-util-$(CONFIG_TRACE) += syscalltbl.o
+perf-util-y += ordered-events.o
+perf-util-y += namespaces.o
+perf-util-y += comm.o
+perf-util-y += thread.o
+perf-util-y += threads.o
+perf-util-y += thread_map.o
+perf-util-y += parse-events-flex.o
+perf-util-y += parse-events-bison.o
+perf-util-y += pmu.o
+perf-util-y += pmus.o
+perf-util-y += pmu-flex.o
+perf-util-y += pmu-bison.o
+perf-util-y += svghelper.o
+perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-info.o
+perf-util-y += trace-event-scripting.o
+perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event.o
+perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-parse.o
+perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-read.o
+perf-util-y += sort.o
+perf-util-y += hist.o
+perf-util-y += util.o
+perf-util-y += cpumap.o
+perf-util-y += affinity.o
+perf-util-y += cputopo.o
+perf-util-y += cgroup.o
+perf-util-y += target.o
+perf-util-y += rblist.o
+perf-util-y += intlist.o
+perf-util-y += vdso.o
+perf-util-y += counts.o
+perf-util-y += stat.o
+perf-util-y += stat-shadow.o
+perf-util-y += stat-display.o
+perf-util-y += perf_api_probe.o
+perf-util-y += record.o
+perf-util-y += srcline.o
+perf-util-y += srccode.o
+perf-util-y += synthetic-events.o
+perf-util-y += data.o
+perf-util-y += tsc.o
+perf-util-y += cloexec.o
+perf-util-y += call-path.o
+perf-util-y += rwsem.o
+perf-util-y += thread-stack.o
+perf-util-y += spark.o
+perf-util-y += topdown.o
+perf-util-y += iostat.o
+perf-util-y += stream.o
+perf-util-$(CONFIG_AUXTRACE) += auxtrace.o
+perf-util-$(CONFIG_AUXTRACE) += intel-pt-decoder/
+perf-util-$(CONFIG_AUXTRACE) += intel-pt.o
+perf-util-$(CONFIG_AUXTRACE) += intel-bts.o
+perf-util-$(CONFIG_AUXTRACE) += arm-spe.o
+perf-util-$(CONFIG_AUXTRACE) += arm-spe-decoder/
+perf-util-$(CONFIG_AUXTRACE) += hisi-ptt.o
+perf-util-$(CONFIG_AUXTRACE) += hisi-ptt-decoder/
+perf-util-$(CONFIG_AUXTRACE) += s390-cpumsf.o
ifdef CONFIG_LIBOPENCSD
-perf-$(CONFIG_AUXTRACE) += cs-etm.o
-perf-$(CONFIG_AUXTRACE) += cs-etm-decoder/
+perf-util-$(CONFIG_AUXTRACE) += cs-etm.o
+perf-util-$(CONFIG_AUXTRACE) += cs-etm-decoder/
endif
-perf-$(CONFIG_AUXTRACE) += cs-etm-base.o
-
-perf-y += parse-branch-options.o
-perf-y += dump-insn.o
-perf-y += parse-regs-options.o
-perf-y += parse-sublevel-options.o
-perf-y += term.o
-perf-y += help-unknown-cmd.o
-perf-y += dlfilter.o
-perf-y += mem-events.o
-perf-y += mem-info.o
-perf-y += vsprintf.o
-perf-y += units.o
-perf-y += time-utils.o
-perf-y += expr-flex.o
-perf-y += expr-bison.o
-perf-y += expr.o
-perf-y += branch.o
-perf-y += mem2node.o
-perf-y += clockid.o
-perf-y += list_sort.o
-perf-y += mutex.o
-perf-y += sharded_mutex.o
-
-perf-$(CONFIG_LIBBPF) += bpf_map.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf_counter.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf_counter_cgroup.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf_ftrace.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf_off_cpu.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf-filter.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf-filter-flex.o
-perf-$(CONFIG_PERF_BPF_SKEL) += bpf-filter-bison.o
+perf-util-$(CONFIG_AUXTRACE) += cs-etm-base.o
+
+perf-util-y += parse-branch-options.o
+perf-util-y += dump-insn.o
+perf-util-y += parse-regs-options.o
+perf-util-y += parse-sublevel-options.o
+perf-util-y += term.o
+perf-util-y += help-unknown-cmd.o
+perf-util-y += dlfilter.o
+perf-util-y += mem-events.o
+perf-util-y += mem-info.o
+perf-util-y += vsprintf.o
+perf-util-y += units.o
+perf-util-y += time-utils.o
+perf-util-y += expr-flex.o
+perf-util-y += expr-bison.o
+perf-util-y += expr.o
+perf-util-y += branch.o
+perf-util-y += mem2node.o
+perf-util-y += clockid.o
+perf-util-y += list_sort.o
+perf-util-y += mutex.o
+perf-util-y += sharded_mutex.o
+
+perf-util-$(CONFIG_LIBBPF) += bpf_map.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_counter.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_counter_cgroup.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_ftrace.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_off_cpu.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf-filter.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf-filter-flex.o
+perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf-filter-bison.o
ifeq ($(CONFIG_LIBTRACEEVENT),y)
- perf-$(CONFIG_PERF_BPF_SKEL) += bpf_lock_contention.o
+ perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_lock_contention.o
endif
ifeq ($(CONFIG_LIBTRACEEVENT),y)
- perf-$(CONFIG_PERF_BPF_SKEL) += bpf_kwork.o
- perf-$(CONFIG_PERF_BPF_SKEL) += bpf_kwork_top.o
+ perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_kwork.o
+ perf-util-$(CONFIG_PERF_BPF_SKEL) += bpf_kwork_top.o
endif
-perf-$(CONFIG_LIBELF) += symbol-elf.o
-perf-$(CONFIG_LIBELF) += probe-file.o
-perf-$(CONFIG_LIBELF) += probe-event.o
+perf-util-$(CONFIG_LIBELF) += symbol-elf.o
+perf-util-$(CONFIG_LIBELF) += probe-file.o
+perf-util-$(CONFIG_LIBELF) += probe-event.o
ifdef CONFIG_LIBBPF_DYNAMIC
hashmap := 1
@@ -185,60 +185,60 @@ ifndef CONFIG_LIBBPF
endif
ifdef hashmap
-perf-y += hashmap.o
+perf-util-y += hashmap.o
endif
ifndef CONFIG_LIBELF
-perf-y += symbol-minimal.o
+perf-util-y += symbol-minimal.o
endif
ifndef CONFIG_SETNS
-perf-y += setns.o
+perf-util-y += setns.o
endif
-perf-$(CONFIG_DWARF) += probe-finder.o
-perf-$(CONFIG_DWARF) += dwarf-aux.o
-perf-$(CONFIG_DWARF) += dwarf-regs.o
-perf-$(CONFIG_DWARF) += debuginfo.o
-perf-$(CONFIG_DWARF) += annotate-data.o
+perf-util-$(CONFIG_DWARF) += probe-finder.o
+perf-util-$(CONFIG_DWARF) += dwarf-aux.o
+perf-util-$(CONFIG_DWARF) += dwarf-regs.o
+perf-util-$(CONFIG_DWARF) += debuginfo.o
+perf-util-$(CONFIG_DWARF) += annotate-data.o
-perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
-perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
-perf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
-perf-$(CONFIG_LIBUNWIND_X86) += libunwind/x86_32.o
-perf-$(CONFIG_LIBUNWIND_AARCH64) += libunwind/arm64.o
+perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
+perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
+perf-util-$(CONFIG_LIBUNWIND_X86) += libunwind/x86_32.o
+perf-util-$(CONFIG_LIBUNWIND_AARCH64) += libunwind/arm64.o
ifeq ($(CONFIG_LIBTRACEEVENT),y)
- perf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
+ perf-util-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
endif
-perf-y += data-convert-json.o
+perf-util-y += data-convert-json.o
-perf-y += scripting-engines/
+perf-util-y += scripting-engines/
-perf-$(CONFIG_ZLIB) += zlib.o
-perf-$(CONFIG_LZMA) += lzma.o
-perf-$(CONFIG_ZSTD) += zstd.o
+perf-util-$(CONFIG_ZLIB) += zlib.o
+perf-util-$(CONFIG_LZMA) += lzma.o
+perf-util-$(CONFIG_ZSTD) += zstd.o
-perf-$(CONFIG_LIBCAP) += cap.o
+perf-util-$(CONFIG_LIBCAP) += cap.o
-perf-$(CONFIG_CXX_DEMANGLE) += demangle-cxx.o
-perf-y += demangle-ocaml.o
-perf-y += demangle-java.o
-perf-y += demangle-rust.o
+perf-util-$(CONFIG_CXX_DEMANGLE) += demangle-cxx.o
+perf-util-y += demangle-ocaml.o
+perf-util-y += demangle-java.o
+perf-util-y += demangle-rust.o
ifdef CONFIG_JITDUMP
-perf-$(CONFIG_LIBELF) += jitdump.o
-perf-$(CONFIG_LIBELF) += genelf.o
-perf-$(CONFIG_DWARF) += genelf_debug.o
+perf-util-$(CONFIG_LIBELF) += jitdump.o
+perf-util-$(CONFIG_LIBELF) += genelf.o
+perf-util-$(CONFIG_DWARF) += genelf_debug.o
endif
-perf-y += perf-hooks.o
+perf-util-y += perf-hooks.o
-perf-$(CONFIG_LIBBPF) += bpf-event.o
-perf-$(CONFIG_LIBBPF) += bpf-utils.o
+perf-util-$(CONFIG_LIBBPF) += bpf-event.o
+perf-util-$(CONFIG_LIBBPF) += bpf-utils.o
-perf-$(CONFIG_LIBPFM4) += pfm.o
+perf-util-$(CONFIG_LIBPFM4) += pfm.o
CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
@@ -403,4 +403,4 @@ $(OUTPUT)%.shellcheck_log: %
$(call rule_mkdir)
$(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false)
-perf-y += $(TEST_LOGS)
+perf-util-y += $(TEST_LOGS)
diff --git a/tools/perf/util/arm-spe-decoder/Build b/tools/perf/util/arm-spe-decoder/Build
index f8dae13fc876..960062b3cb9e 100644
--- a/tools/perf/util/arm-spe-decoder/Build
+++ b/tools/perf/util/arm-spe-decoder/Build
@@ -1 +1 @@
-perf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o arm-spe-decoder.o
+perf-util-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o arm-spe-decoder.o
diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c
index a454c6737563..7bf607d0f6d8 100644
--- a/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c
+++ b/tools/perf/util/arm-spe-decoder/arm-spe-pkt-decoder.c
@@ -10,24 +10,11 @@
#include <byteswap.h>
#include <linux/bitops.h>
#include <stdarg.h>
+#include <linux/kernel.h>
+#include <asm-generic/unaligned.h>
#include "arm-spe-pkt-decoder.h"
-#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#define le16_to_cpu bswap_16
-#define le32_to_cpu bswap_32
-#define le64_to_cpu bswap_64
-#define memcpy_le64(d, s, n) do { \
- memcpy((d), (s), (n)); \
- *(d) = le64_to_cpu(*(d)); \
-} while (0)
-#else
-#define le16_to_cpu
-#define le32_to_cpu
-#define le64_to_cpu
-#define memcpy_le64 memcpy
-#endif
-
static const char * const arm_spe_packet_name[] = {
[ARM_SPE_PAD] = "PAD",
[ARM_SPE_END] = "END",
@@ -70,9 +57,9 @@ static int arm_spe_get_payload(const unsigned char *buf, size_t len,
switch (payload_len) {
case 1: packet->payload = *(uint8_t *)buf; break;
- case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
- case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
- case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
+ case 2: packet->payload = get_unaligned_le16(buf); break;
+ case 4: packet->payload = get_unaligned_le32(buf); break;
+ case 8: packet->payload = get_unaligned_le64(buf); break;
default: return ARM_SPE_BAD_PACKET;
}
diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c
index b51544996046..04f98b6bb291 100644
--- a/tools/perf/util/bpf-filter.c
+++ b/tools/perf/util/bpf-filter.c
@@ -17,11 +17,11 @@
#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
-#define __PERF_SAMPLE_TYPE(st, opt) { st, #st, opt }
-#define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PERF_SAMPLE_##_st, opt)
+#define __PERF_SAMPLE_TYPE(tt, st, opt) { tt, #st, opt }
+#define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PBF_TERM_##_st, PERF_SAMPLE_##_st, opt)
static const struct perf_sample_info {
- u64 type;
+ enum perf_bpf_filter_term type;
const char *name;
const char *option;
} sample_table[] = {
@@ -44,12 +44,12 @@ static const struct perf_sample_info {
PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"),
};
-static const struct perf_sample_info *get_sample_info(u64 flags)
+static const struct perf_sample_info *get_sample_info(enum perf_bpf_filter_term type)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(sample_table); i++) {
- if (sample_table[i].type == flags)
+ if (sample_table[i].type == type)
return &sample_table[i];
}
return NULL;
@@ -59,9 +59,15 @@ static int check_sample_flags(struct evsel *evsel, struct perf_bpf_filter_expr *
{
const struct perf_sample_info *info;
- if (evsel->core.attr.sample_type & expr->sample_flags)
+ if (expr->term >= PBF_TERM_SAMPLE_START && expr->term <= PBF_TERM_SAMPLE_END &&
+ (evsel->core.attr.sample_type & (1 << (expr->term - PBF_TERM_SAMPLE_START))))
return 0;
+ if (expr->term == PBF_TERM_UID || expr->term == PBF_TERM_GID) {
+ /* Not dependent on the sample_type as computed from a BPF helper. */
+ return 0;
+ }
+
if (expr->op == PBF_OP_GROUP_BEGIN) {
struct perf_bpf_filter_expr *group;
@@ -72,10 +78,10 @@ static int check_sample_flags(struct evsel *evsel, struct perf_bpf_filter_expr *
return 0;
}
- info = get_sample_info(expr->sample_flags);
+ info = get_sample_info(expr->term);
if (info == NULL) {
- pr_err("Error: %s event does not have sample flags %lx\n",
- evsel__name(evsel), expr->sample_flags);
+ pr_err("Error: %s event does not have sample flags %d\n",
+ evsel__name(evsel), expr->term);
return -1;
}
@@ -105,7 +111,7 @@ int perf_bpf_filter__prepare(struct evsel *evsel)
struct perf_bpf_filter_entry entry = {
.op = expr->op,
.part = expr->part,
- .flags = expr->sample_flags,
+ .term = expr->term,
.value = expr->val,
};
@@ -122,7 +128,7 @@ int perf_bpf_filter__prepare(struct evsel *evsel)
struct perf_bpf_filter_entry group_entry = {
.op = group->op,
.part = group->part,
- .flags = group->sample_flags,
+ .term = group->term,
.value = group->val,
};
bpf_map_update_elem(fd, &i, &group_entry, BPF_ANY);
@@ -173,7 +179,8 @@ u64 perf_bpf_filter__lost_count(struct evsel *evsel)
return skel ? skel->bss->dropped : 0;
}
-struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, int part,
+struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term term,
+ int part,
enum perf_bpf_filter_op op,
unsigned long val)
{
@@ -181,7 +188,7 @@ struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flag
expr = malloc(sizeof(*expr));
if (expr != NULL) {
- expr->sample_flags = sample_flags;
+ expr->term = term;
expr->part = part;
expr->op = op;
expr->val = val;
diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h
index 7afd159411b8..cd6764442c16 100644
--- a/tools/perf/util/bpf-filter.h
+++ b/tools/perf/util/bpf-filter.h
@@ -11,14 +11,15 @@ struct perf_bpf_filter_expr {
struct list_head groups;
enum perf_bpf_filter_op op;
int part;
- unsigned long sample_flags;
+ enum perf_bpf_filter_term term;
unsigned long val;
};
struct evsel;
#ifdef HAVE_BPF_SKEL
-struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, int part,
+struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term term,
+ int part,
enum perf_bpf_filter_op op,
unsigned long val);
int perf_bpf_filter__parse(struct list_head *expr_head, const char *str);
diff --git a/tools/perf/util/bpf-filter.l b/tools/perf/util/bpf-filter.l
index d4ff0f1345cd..2a7c839f3fae 100644
--- a/tools/perf/util/bpf-filter.l
+++ b/tools/perf/util/bpf-filter.l
@@ -9,16 +9,16 @@
#include "bpf-filter.h"
#include "bpf-filter-bison.h"
-static int sample(unsigned long sample_flag)
+static int sample(enum perf_bpf_filter_term term)
{
- perf_bpf_filter_lval.sample.type = sample_flag;
+ perf_bpf_filter_lval.sample.term = term;
perf_bpf_filter_lval.sample.part = 0;
return BFT_SAMPLE;
}
-static int sample_part(unsigned long sample_flag, int part)
+static int sample_part(enum perf_bpf_filter_term term, int part)
{
- perf_bpf_filter_lval.sample.type = sample_flag;
+ perf_bpf_filter_lval.sample.term = term;
perf_bpf_filter_lval.sample.part = part;
return BFT_SAMPLE;
}
@@ -67,34 +67,36 @@ ident [_a-zA-Z][_a-zA-Z0-9]+
{num_hex} { return value(16); }
{space} { }
-ip { return sample(PERF_SAMPLE_IP); }
-id { return sample(PERF_SAMPLE_ID); }
-tid { return sample(PERF_SAMPLE_TID); }
-pid { return sample_part(PERF_SAMPLE_TID, 1); }
-cpu { return sample(PERF_SAMPLE_CPU); }
-time { return sample(PERF_SAMPLE_TIME); }
-addr { return sample(PERF_SAMPLE_ADDR); }
-period { return sample(PERF_SAMPLE_PERIOD); }
-txn { return sample(PERF_SAMPLE_TRANSACTION); }
-weight { return sample(PERF_SAMPLE_WEIGHT); }
-weight1 { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 1); }
-weight2 { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 2); }
-weight3 { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 3); }
-ins_lat { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 2); } /* alias for weight2 */
-p_stage_cyc { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 3); } /* alias for weight3 */
-retire_lat { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 3); } /* alias for weight3 */
-phys_addr { return sample(PERF_SAMPLE_PHYS_ADDR); }
-code_pgsz { return sample(PERF_SAMPLE_CODE_PAGE_SIZE); }
-data_pgsz { return sample(PERF_SAMPLE_DATA_PAGE_SIZE); }
-mem_op { return sample_part(PERF_SAMPLE_DATA_SRC, 1); }
-mem_lvlnum { return sample_part(PERF_SAMPLE_DATA_SRC, 2); }
-mem_lvl { return sample_part(PERF_SAMPLE_DATA_SRC, 2); } /* alias for mem_lvlnum */
-mem_snoop { return sample_part(PERF_SAMPLE_DATA_SRC, 3); } /* include snoopx */
-mem_remote { return sample_part(PERF_SAMPLE_DATA_SRC, 4); }
-mem_lock { return sample_part(PERF_SAMPLE_DATA_SRC, 5); }
-mem_dtlb { return sample_part(PERF_SAMPLE_DATA_SRC, 6); }
-mem_blk { return sample_part(PERF_SAMPLE_DATA_SRC, 7); }
-mem_hops { return sample_part(PERF_SAMPLE_DATA_SRC, 8); }
+ip { return sample(PBF_TERM_IP); }
+id { return sample(PBF_TERM_ID); }
+tid { return sample(PBF_TERM_TID); }
+pid { return sample_part(PBF_TERM_TID, 1); }
+cpu { return sample(PBF_TERM_CPU); }
+time { return sample(PBF_TERM_TIME); }
+addr { return sample(PBF_TERM_ADDR); }
+period { return sample(PBF_TERM_PERIOD); }
+txn { return sample(PBF_TERM_TRANSACTION); }
+weight { return sample(PBF_TERM_WEIGHT); }
+weight1 { return sample_part(PBF_TERM_WEIGHT_STRUCT, 1); }
+weight2 { return sample_part(PBF_TERM_WEIGHT_STRUCT, 2); }
+weight3 { return sample_part(PBF_TERM_WEIGHT_STRUCT, 3); }
+ins_lat { return sample_part(PBF_TERM_WEIGHT_STRUCT, 2); } /* alias for weight2 */
+p_stage_cyc { return sample_part(PBF_TERM_WEIGHT_STRUCT, 3); } /* alias for weight3 */
+retire_lat { return sample_part(PBF_TERM_WEIGHT_STRUCT, 3); } /* alias for weight3 */
+phys_addr { return sample(PBF_TERM_PHYS_ADDR); }
+code_pgsz { return sample(PBF_TERM_CODE_PAGE_SIZE); }
+data_pgsz { return sample(PBF_TERM_DATA_PAGE_SIZE); }
+mem_op { return sample_part(PBF_TERM_DATA_SRC, 1); }
+mem_lvlnum { return sample_part(PBF_TERM_DATA_SRC, 2); }
+mem_lvl { return sample_part(PBF_TERM_DATA_SRC, 2); } /* alias for mem_lvlnum */
+mem_snoop { return sample_part(PBF_TERM_DATA_SRC, 3); } /* include snoopx */
+mem_remote { return sample_part(PBF_TERM_DATA_SRC, 4); }
+mem_lock { return sample_part(PBF_TERM_DATA_SRC, 5); }
+mem_dtlb { return sample_part(PBF_TERM_DATA_SRC, 6); }
+mem_blk { return sample_part(PBF_TERM_DATA_SRC, 7); }
+mem_hops { return sample_part(PBF_TERM_DATA_SRC, 8); }
+uid { return sample(PBF_TERM_UID); }
+gid { return sample(PBF_TERM_GID); }
"==" { return operator(PBF_OP_EQ); }
"!=" { return operator(PBF_OP_NEQ); }
diff --git a/tools/perf/util/bpf-filter.y b/tools/perf/util/bpf-filter.y
index 0e4d6de3c2ad..0c56fccb8874 100644
--- a/tools/perf/util/bpf-filter.y
+++ b/tools/perf/util/bpf-filter.y
@@ -27,7 +27,7 @@ static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
{
unsigned long num;
struct {
- unsigned long type;
+ enum perf_bpf_filter_term term;
int part;
} sample;
enum perf_bpf_filter_op op;
@@ -62,7 +62,8 @@ filter_term BFT_LOGICAL_OR filter_expr
if ($1->op == PBF_OP_GROUP_BEGIN) {
expr = $1;
} else {
- expr = perf_bpf_filter_expr__new(0, 0, PBF_OP_GROUP_BEGIN, 1);
+ expr = perf_bpf_filter_expr__new(PBF_TERM_NONE, /*part=*/0,
+ PBF_OP_GROUP_BEGIN, /*val=*/1);
list_add_tail(&$1->list, &expr->groups);
}
expr->val++;
@@ -78,7 +79,7 @@ filter_expr
filter_expr:
BFT_SAMPLE BFT_OP BFT_NUM
{
- $$ = perf_bpf_filter_expr__new($1.type, $1.part, $2, $3);
+ $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3);
}
%%
diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf_skel/sample-filter.h
index 2e96e1ab084a..350efa121026 100644
--- a/tools/perf/util/bpf_skel/sample-filter.h
+++ b/tools/perf/util/bpf_skel/sample-filter.h
@@ -16,12 +16,48 @@ enum perf_bpf_filter_op {
PBF_OP_GROUP_END,
};
+enum perf_bpf_filter_term {
+ /* No term is in use. */
+ PBF_TERM_NONE = 0,
+ /* Terms that correspond to PERF_SAMPLE_xx values. */
+ PBF_TERM_SAMPLE_START = PBF_TERM_NONE + 1,
+ PBF_TERM_IP = PBF_TERM_SAMPLE_START + 0, /* SAMPLE_IP = 1U << 0 */
+ PBF_TERM_TID = PBF_TERM_SAMPLE_START + 1, /* SAMPLE_TID = 1U << 1 */
+ PBF_TERM_TIME = PBF_TERM_SAMPLE_START + 2, /* SAMPLE_TIME = 1U << 2 */
+ PBF_TERM_ADDR = PBF_TERM_SAMPLE_START + 3, /* SAMPLE_ADDR = 1U << 3 */
+ __PBF_UNUSED_TERM4 = PBF_TERM_SAMPLE_START + 4, /* SAMPLE_READ = 1U << 4 */
+ __PBF_UNUSED_TERM5 = PBF_TERM_SAMPLE_START + 5, /* SAMPLE_CALLCHAIN = 1U << 5 */
+ PBF_TERM_ID = PBF_TERM_SAMPLE_START + 6, /* SAMPLE_ID = 1U << 6 */
+ PBF_TERM_CPU = PBF_TERM_SAMPLE_START + 7, /* SAMPLE_CPU = 1U << 7 */
+ PBF_TERM_PERIOD = PBF_TERM_SAMPLE_START + 8, /* SAMPLE_PERIOD = 1U << 8 */
+ __PBF_UNUSED_TERM9 = PBF_TERM_SAMPLE_START + 9, /* SAMPLE_STREAM_ID = 1U << 9 */
+ __PBF_UNUSED_TERM10 = PBF_TERM_SAMPLE_START + 10, /* SAMPLE_RAW = 1U << 10 */
+ __PBF_UNUSED_TERM11 = PBF_TERM_SAMPLE_START + 11, /* SAMPLE_BRANCH_STACK = 1U << 11 */
+ __PBF_UNUSED_TERM12 = PBF_TERM_SAMPLE_START + 12, /* SAMPLE_REGS_USER = 1U << 12 */
+ __PBF_UNUSED_TERM13 = PBF_TERM_SAMPLE_START + 13, /* SAMPLE_STACK_USER = 1U << 13 */
+ PBF_TERM_WEIGHT = PBF_TERM_SAMPLE_START + 14, /* SAMPLE_WEIGHT = 1U << 14 */
+ PBF_TERM_DATA_SRC = PBF_TERM_SAMPLE_START + 15, /* SAMPLE_DATA_SRC = 1U << 15 */
+ __PBF_UNUSED_TERM16 = PBF_TERM_SAMPLE_START + 16, /* SAMPLE_IDENTIFIER = 1U << 16 */
+ PBF_TERM_TRANSACTION = PBF_TERM_SAMPLE_START + 17, /* SAMPLE_TRANSACTION = 1U << 17 */
+ __PBF_UNUSED_TERM18 = PBF_TERM_SAMPLE_START + 18, /* SAMPLE_REGS_INTR = 1U << 18 */
+ PBF_TERM_PHYS_ADDR = PBF_TERM_SAMPLE_START + 19, /* SAMPLE_PHYS_ADDR = 1U << 19 */
+ __PBF_UNUSED_TERM20 = PBF_TERM_SAMPLE_START + 20, /* SAMPLE_AUX = 1U << 20 */
+ __PBF_UNUSED_TERM21 = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */
+ PBF_TERM_DATA_PAGE_SIZE = PBF_TERM_SAMPLE_START + 22, /* SAMPLE_DATA_PAGE_SIZE = 1U << 22 */
+ PBF_TERM_CODE_PAGE_SIZE = PBF_TERM_SAMPLE_START + 23, /* SAMPLE_CODE_PAGE_SIZE = 1U << 23 */
+ PBF_TERM_WEIGHT_STRUCT = PBF_TERM_SAMPLE_START + 24, /* SAMPLE_WEIGHT_STRUCT = 1U << 24 */
+ PBF_TERM_SAMPLE_END = PBF_TERM_WEIGHT_STRUCT,
+ /* Terms computed from BPF helpers. */
+ PBF_TERM_UID,
+ PBF_TERM_GID,
+};
+
/* BPF map entry for filtering */
struct perf_bpf_filter_entry {
enum perf_bpf_filter_op op;
__u32 part; /* sub-sample type info when it has multiple values */
- __u64 flags; /* perf sample type flags */
+ enum perf_bpf_filter_term term;
__u64 value;
};
-#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */ \ No newline at end of file
+#endif /* PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H */
diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util/bpf_skel/sample_filter.bpf.c
index fb94f5280626..f59985101973 100644
--- a/tools/perf/util/bpf_skel/sample_filter.bpf.c
+++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c
@@ -48,31 +48,54 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
{
struct perf_sample_data___new *data = (void *)kctx->data;
- if (!bpf_core_field_exists(data->sample_flags) ||
- (data->sample_flags & entry->flags) == 0)
+ if (!bpf_core_field_exists(data->sample_flags))
return 0;
- switch (entry->flags) {
- case PERF_SAMPLE_IP:
+#define BUILD_CHECK_SAMPLE(x) \
+ _Static_assert((1 << (PBF_TERM_##x - PBF_TERM_SAMPLE_START)) == PERF_SAMPLE_##x, \
+ "Mismatched PBF term to sample bit " #x)
+ BUILD_CHECK_SAMPLE(IP);
+ BUILD_CHECK_SAMPLE(TID);
+ BUILD_CHECK_SAMPLE(TIME);
+ BUILD_CHECK_SAMPLE(ADDR);
+ BUILD_CHECK_SAMPLE(ID);
+ BUILD_CHECK_SAMPLE(CPU);
+ BUILD_CHECK_SAMPLE(PERIOD);
+ BUILD_CHECK_SAMPLE(WEIGHT);
+ BUILD_CHECK_SAMPLE(DATA_SRC);
+ BUILD_CHECK_SAMPLE(TRANSACTION);
+ BUILD_CHECK_SAMPLE(PHYS_ADDR);
+ BUILD_CHECK_SAMPLE(DATA_PAGE_SIZE);
+ BUILD_CHECK_SAMPLE(CODE_PAGE_SIZE);
+ BUILD_CHECK_SAMPLE(WEIGHT_STRUCT);
+#undef BUILD_CHECK_SAMPLE
+
+ /* For sample terms check the sample bit is set. */
+ if (entry->term >= PBF_TERM_SAMPLE_START && entry->term <= PBF_TERM_SAMPLE_END &&
+ (data->sample_flags & (1 << (entry->term - PBF_TERM_SAMPLE_START))) == 0)
+ return 0;
+
+ switch (entry->term) {
+ case PBF_TERM_IP:
return kctx->data->ip;
- case PERF_SAMPLE_ID:
+ case PBF_TERM_ID:
return kctx->data->id;
- case PERF_SAMPLE_TID:
+ case PBF_TERM_TID:
if (entry->part)
return kctx->data->tid_entry.pid;
else
return kctx->data->tid_entry.tid;
- case PERF_SAMPLE_CPU:
+ case PBF_TERM_CPU:
return kctx->data->cpu_entry.cpu;
- case PERF_SAMPLE_TIME:
+ case PBF_TERM_TIME:
return kctx->data->time;
- case PERF_SAMPLE_ADDR:
+ case PBF_TERM_ADDR:
return kctx->data->addr;
- case PERF_SAMPLE_PERIOD:
+ case PBF_TERM_PERIOD:
return kctx->data->period;
- case PERF_SAMPLE_TRANSACTION:
+ case PBF_TERM_TRANSACTION:
return kctx->data->txn;
- case PERF_SAMPLE_WEIGHT_STRUCT:
+ case PBF_TERM_WEIGHT_STRUCT:
if (entry->part == 1)
return kctx->data->weight.var1_dw;
if (entry->part == 2)
@@ -80,15 +103,15 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
if (entry->part == 3)
return kctx->data->weight.var3_w;
/* fall through */
- case PERF_SAMPLE_WEIGHT:
+ case PBF_TERM_WEIGHT:
return kctx->data->weight.full;
- case PERF_SAMPLE_PHYS_ADDR:
+ case PBF_TERM_PHYS_ADDR:
return kctx->data->phys_addr;
- case PERF_SAMPLE_CODE_PAGE_SIZE:
+ case PBF_TERM_CODE_PAGE_SIZE:
return kctx->data->code_page_size;
- case PERF_SAMPLE_DATA_PAGE_SIZE:
+ case PBF_TERM_DATA_PAGE_SIZE:
return kctx->data->data_page_size;
- case PERF_SAMPLE_DATA_SRC:
+ case PBF_TERM_DATA_SRC:
if (entry->part == 1)
return kctx->data->data_src.mem_op;
if (entry->part == 2)
@@ -117,6 +140,22 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
}
/* return the whole word */
return kctx->data->data_src.val;
+ case PBF_TERM_UID:
+ return bpf_get_current_uid_gid() & 0xFFFFFFFF;
+ case PBF_TERM_GID:
+ return bpf_get_current_uid_gid() >> 32;
+ case PBF_TERM_NONE:
+ case __PBF_UNUSED_TERM4:
+ case __PBF_UNUSED_TERM5:
+ case __PBF_UNUSED_TERM9:
+ case __PBF_UNUSED_TERM10:
+ case __PBF_UNUSED_TERM11:
+ case __PBF_UNUSED_TERM12:
+ case __PBF_UNUSED_TERM13:
+ case __PBF_UNUSED_TERM16:
+ case __PBF_UNUSED_TERM18:
+ case __PBF_UNUSED_TERM20:
+ case __PBF_UNUSED_TERM21:
default:
break;
}
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index 233f2b6edf52..49b79cf0c5cc 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -86,14 +86,6 @@ static struct comm_str *comm_str__new(const char *str)
return result;
}
-static int comm_str__cmp(const void *_lhs, const void *_rhs)
-{
- const struct comm_str *lhs = *(const struct comm_str * const *)_lhs;
- const struct comm_str *rhs = *(const struct comm_str * const *)_rhs;
-
- return strcmp(comm_str__str(lhs), comm_str__str(rhs));
-}
-
static int comm_str__search(const void *_key, const void *_member)
{
const char *key = _key;
@@ -169,9 +161,24 @@ static struct comm_str *comm_strs__findnew(const char *str)
}
result = comm_str__new(str);
if (result) {
- comm_strs->strs[comm_strs->num_strs++] = result;
- qsort(comm_strs->strs, comm_strs->num_strs, sizeof(struct comm_str *),
- comm_str__cmp);
+ int low = 0, high = comm_strs->num_strs - 1;
+ int insert = comm_strs->num_strs; /* Default to inserting at the end. */
+
+ while (low <= high) {
+ int mid = low + (high - low) / 2;
+ int cmp = strcmp(comm_str__str(comm_strs->strs[mid]), str);
+
+ if (cmp < 0) {
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ insert = mid;
+ }
+ }
+ memmove(&comm_strs->strs[insert + 1], &comm_strs->strs[insert],
+ (comm_strs->num_strs - insert) * sizeof(struct comm_str *));
+ comm_strs->num_strs++;
+ comm_strs->strs[insert] = result;
}
}
up_write(&comm_strs->lock);
diff --git a/tools/perf/util/cs-etm-decoder/Build b/tools/perf/util/cs-etm-decoder/Build
index 216cb17a3322..056d665f7f88 100644
--- a/tools/perf/util/cs-etm-decoder/Build
+++ b/tools/perf/util/cs-etm-decoder/Build
@@ -1 +1 @@
-perf-$(CONFIG_AUXTRACE) += cs-etm-decoder.o
+perf-util-$(CONFIG_AUXTRACE) += cs-etm-decoder.o
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 32818bd7cd17..5e9fbcfad7d4 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1013,7 +1013,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
if (!dso)
goto out;
- if (dso->data.status == DSO_DATA_STATUS_ERROR &&
+ if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR &&
dso__data_status_seen(dso, DSO_DATA_STATUS_SEEN_ITRACE))
goto out;
@@ -1027,11 +1027,11 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
if (len <= 0) {
ui__warning_once("CS ETM Trace: Missing DSO. Use 'perf archive' or debuginfod to export data from the traced system.\n"
" Enable CONFIG_PROC_KCORE or use option '-k /path/to/vmlinux' for kernel symbols.\n");
- if (!dso->auxtrace_warned) {
+ if (!dso__auxtrace_warned(dso)) {
pr_err("CS ETM Trace: Debug data not found for address %#"PRIx64" in %s\n",
- address,
- dso->long_name ? dso->long_name : "Unknown");
- dso->auxtrace_warned = true;
+ address,
+ dso__long_name(dso) ? dso__long_name(dso) : "Unknown");
+ dso__set_auxtrace_warned(dso);
}
goto out;
}
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 72aec8f61b94..e10558b79504 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -1199,7 +1199,7 @@ static int symbol__disassemble_bpf(struct symbol *sym,
int ret;
FILE *s;
- if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
+ if (dso__binary_type(dso) != DSO_BINARY_TYPE__BPF_PROG_INFO)
return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE;
pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__,
@@ -1226,14 +1226,14 @@ static int symbol__disassemble_bpf(struct symbol *sym,
info.arch = bfd_get_arch(bfdf);
info.mach = bfd_get_mach(bfdf);
- info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
- dso->bpf_prog.id);
+ info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env,
+ dso__bpf_prog(dso)->id);
if (!info_node) {
ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
goto out;
}
info_linear = info_node->info_linear;
- sub_id = dso->bpf_prog.sub_id;
+ sub_id = dso__bpf_prog(dso)->sub_id;
info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns);
info.buffer_length = info_linear->info.jited_prog_len;
@@ -1244,7 +1244,7 @@ static int symbol__disassemble_bpf(struct symbol *sym,
if (info_linear->info.btf_id) {
struct btf_node *node;
- node = perf_env__find_btf(dso->bpf_prog.env,
+ node = perf_env__find_btf(dso__bpf_prog(dso)->env,
info_linear->info.btf_id);
if (node)
btf = btf__new((__u8 *)(node->data),
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index dde706b71da7..2340c4f6d0c2 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1652,3 +1652,15 @@ int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
return 0;
}
+
+bool perf_pid_map_tid(const char *dso_name, int *tid)
+{
+ return sscanf(dso_name, "/tmp/perf-%d.map", tid) == 1;
+}
+
+bool is_perf_pid_map_name(const char *dso_name)
+{
+ int tid;
+
+ return perf_pid_map_tid(dso_name, &tid);
+}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index df2c98402af3..878c1f441868 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -280,6 +280,16 @@ static inline void dso__set_annotate_warned(struct dso *dso)
RC_CHK_ACCESS(dso)->annotate_warned = 1;
}
+static inline bool dso__auxtrace_warned(const struct dso *dso)
+{
+ return RC_CHK_ACCESS(dso)->auxtrace_warned;
+}
+
+static inline void dso__set_auxtrace_warned(struct dso *dso)
+{
+ RC_CHK_ACCESS(dso)->auxtrace_warned = 1;
+}
+
static inline struct auxtrace_cache *dso__auxtrace_cache(struct dso *dso)
{
return RC_CHK_ACCESS(dso)->auxtrace_cache;
@@ -809,4 +819,8 @@ void reset_fd_limit(void);
u64 dso__find_global_type(struct dso *dso, u64 addr);
u64 dso__findnew_global_type(struct dso *dso, u64 addr, u64 offset);
+/* Check if dso name is of format "/tmp/perf-%d.map" */
+bool perf_pid_map_tid(const char *dso_name, int *tid);
+bool is_perf_pid_map_name(const char *dso_name);
+
#endif /* __PERF_DSO */
diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c
index ab3d0c01dd63..d4acdb37f046 100644
--- a/tools/perf/util/dsos.c
+++ b/tools/perf/util/dsos.c
@@ -164,6 +164,9 @@ static struct dso *__dsos__find_by_longname_id(struct dsos *dsos,
};
struct dso **res;
+ if (dsos->dsos == NULL)
+ return NULL;
+
if (!dsos->sorted) {
if (!write_locked) {
struct dso *dso;
@@ -203,11 +206,27 @@ int __dsos__add(struct dsos *dsos, struct dso *dso)
dsos->dsos = temp;
dsos->allocated = to_allocate;
}
- dsos->dsos[dsos->cnt++] = dso__get(dso);
- if (dsos->cnt >= 2 && dsos->sorted) {
- dsos->sorted = dsos__cmp_long_name_id_short_name(&dsos->dsos[dsos->cnt - 2],
- &dsos->dsos[dsos->cnt - 1])
- <= 0;
+ if (!dsos->sorted) {
+ dsos->dsos[dsos->cnt++] = dso__get(dso);
+ } else {
+ int low = 0, high = dsos->cnt - 1;
+ int insert = dsos->cnt; /* Default to inserting at the end. */
+
+ while (low <= high) {
+ int mid = low + (high - low) / 2;
+ int cmp = dsos__cmp_long_name_id_short_name(&dsos->dsos[mid], &dso);
+
+ if (cmp < 0) {
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ insert = mid;
+ }
+ }
+ memmove(&dsos->dsos[insert + 1], &dsos->dsos[insert],
+ (dsos->cnt - insert) * sizeof(struct dso *));
+ dsos->cnt++;
+ dsos->dsos[insert] = dso__get(dso);
}
dso__set_dsos(dso, dsos);
return 0;
@@ -275,7 +294,7 @@ static void dso__set_basename(struct dso *dso)
char *base, *lname;
int tid;
- if (sscanf(dso__long_name(dso), "/tmp/perf-%d.map", &tid) == 1) {
+ if (perf_pid_map_tid(dso__long_name(dso), &tid)) {
if (asprintf(&base, "[JIT] tid %d", tid) < 0)
return;
} else {
diff --git a/tools/perf/util/events_stats.h b/tools/perf/util/events_stats.h
index 8fecc9fbaecc..f43e5b1a366a 100644
--- a/tools/perf/util/events_stats.h
+++ b/tools/perf/util/events_stats.h
@@ -52,7 +52,6 @@ struct hists_stats {
void events_stats__inc(struct events_stats *stats, u32 type);
-size_t events_stats__fprintf(struct events_stats *stats, FILE *fp,
- bool skip_empty);
+size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
#endif /* __PERF_EVENTS_STATS_ */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 4f818ab6b662..bc603193c477 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -10,6 +10,7 @@
#include <errno.h>
#include <inttypes.h>
#include <linux/bitops.h>
+#include <api/io.h>
#include <api/fs/fs.h>
#include <api/fs/tracing_path.h>
#include <linux/hw_breakpoint.h>
@@ -30,6 +31,7 @@
#include "counts.h"
#include "event.h"
#include "evsel.h"
+#include "time-utils.h"
#include "util/env.h"
#include "util/evsel_config.h"
#include "util/evsel_fprintf.h"
@@ -53,6 +55,7 @@
#include "../perf-sys.h"
#include "util/parse-branch-options.h"
#include "util/bpf-filter.h"
+#include "util/hist.h"
#include <internal/xyarray.h>
#include <internal/lib.h>
#include <internal/threadmap.h>
@@ -830,16 +833,22 @@ const char *evsel__group_name(struct evsel *evsel)
int evsel__group_desc(struct evsel *evsel, char *buf, size_t size)
{
int ret = 0;
+ bool first = true;
struct evsel *pos;
const char *group_name = evsel__group_name(evsel);
if (!evsel->forced_leader)
ret = scnprintf(buf, size, "%s { ", group_name);
- ret += scnprintf(buf + ret, size - ret, "%s", evsel__name(evsel));
+ for_each_group_evsel(pos, evsel) {
+ if (symbol_conf.skip_empty &&
+ evsel__hists(pos)->stats.nr_samples == 0)
+ continue;
- for_each_group_member(pos, evsel)
- ret += scnprintf(buf + ret, size - ret, ", %s", evsel__name(pos));
+ ret += scnprintf(buf + ret, size - ret, "%s%s",
+ first ? "" : ", ", evsel__name(pos));
+ first = false;
+ }
if (!evsel->forced_leader)
ret += scnprintf(buf + ret, size - ret, " }");
@@ -1493,6 +1502,9 @@ void evsel__exit(struct evsel *evsel)
evsel->per_pkg_mask = NULL;
zfree(&evsel->metric_events);
perf_evsel__object.fini(evsel);
+ if (evsel->tool_event == PERF_TOOL_SYSTEM_TIME ||
+ evsel->tool_event == PERF_TOOL_USER_TIME)
+ xyarray__delete(evsel->start_times);
}
void evsel__delete(struct evsel *evsel)
@@ -1606,11 +1618,173 @@ static int evsel__read_group(struct evsel *leader, int cpu_map_idx, int thread)
return evsel__process_group_data(leader, cpu_map_idx, thread, data);
}
+static bool read_until_char(struct io *io, char e)
+{
+ int c;
+
+ do {
+ c = io__get_char(io);
+ if (c == -1)
+ return false;
+ } while (c != e);
+ return true;
+}
+
+static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val)
+{
+ char buf[256];
+ struct io io;
+ int i;
+
+ io__init(&io, fd, buf, sizeof(buf));
+
+ /* Skip lines to relevant CPU. */
+ for (i = -1; i < cpu.cpu; i++) {
+ if (!read_until_char(&io, '\n'))
+ return -EINVAL;
+ }
+ /* Skip to "cpu". */
+ if (io__get_char(&io) != 'c') return -EINVAL;
+ if (io__get_char(&io) != 'p') return -EINVAL;
+ if (io__get_char(&io) != 'u') return -EINVAL;
+
+ /* Skip N of cpuN. */
+ if (!read_until_char(&io, ' '))
+ return -EINVAL;
+
+ i = 1;
+ while (true) {
+ if (io__get_dec(&io, val) != ' ')
+ break;
+ if (field == i)
+ return 0;
+ i++;
+ }
+ return -EINVAL;
+}
+
+static int read_pid_stat_field(int fd, int field, __u64 *val)
+{
+ char buf[256];
+ struct io io;
+ int c, i;
+
+ io__init(&io, fd, buf, sizeof(buf));
+ if (io__get_dec(&io, val) != ' ')
+ return -EINVAL;
+ if (field == 1)
+ return 0;
+
+ /* Skip comm. */
+ if (io__get_char(&io) != '(' || !read_until_char(&io, ')'))
+ return -EINVAL;
+ if (field == 2)
+ return -EINVAL; /* String can't be returned. */
+
+ /* Skip state */
+ if (io__get_char(&io) != ' ' || io__get_char(&io) == -1)
+ return -EINVAL;
+ if (field == 3)
+ return -EINVAL; /* String can't be returned. */
+
+ /* Loop over numeric fields*/
+ if (io__get_char(&io) != ' ')
+ return -EINVAL;
+
+ i = 4;
+ while (true) {
+ c = io__get_dec(&io, val);
+ if (c == -1)
+ return -EINVAL;
+ if (c == -2) {
+ /* Assume a -ve was read */
+ c = io__get_dec(&io, val);
+ *val *= -1;
+ }
+ if (c != ' ')
+ return -EINVAL;
+ if (field == i)
+ return 0;
+ i++;
+ }
+ return -EINVAL;
+}
+
+static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread)
+{
+ __u64 *start_time, cur_time, delta_start;
+ int fd, err = 0;
+ struct perf_counts_values *count;
+ bool adjust = false;
+
+ count = perf_counts(evsel->counts, cpu_map_idx, thread);
+
+ switch (evsel->tool_event) {
+ case PERF_TOOL_DURATION_TIME:
+ /*
+ * Pretend duration_time is only on the first CPU and thread, or
+ * else aggregation will scale duration_time by the number of
+ * CPUs/threads.
+ */
+ start_time = &evsel->start_time;
+ if (cpu_map_idx == 0 && thread == 0)
+ cur_time = rdclock();
+ else
+ cur_time = *start_time;
+ break;
+ case PERF_TOOL_USER_TIME:
+ case PERF_TOOL_SYSTEM_TIME: {
+ bool system = evsel->tool_event == PERF_TOOL_SYSTEM_TIME;
+
+ start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread);
+ fd = FD(evsel, cpu_map_idx, thread);
+ lseek(fd, SEEK_SET, 0);
+ if (evsel->pid_stat) {
+ /* The event exists solely on 1 CPU. */
+ if (cpu_map_idx == 0)
+ err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time);
+ else
+ cur_time = 0;
+ } else {
+ /* The event is for all threads. */
+ if (thread == 0) {
+ struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus,
+ cpu_map_idx);
+
+ err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time);
+ } else {
+ cur_time = 0;
+ }
+ }
+ adjust = true;
+ break;
+ }
+ case PERF_TOOL_NONE:
+ case PERF_TOOL_MAX:
+ default:
+ err = -EINVAL;
+ }
+ if (err)
+ return err;
+
+ delta_start = cur_time - *start_time;
+ if (adjust) {
+ __u64 ticks_per_sec = sysconf(_SC_CLK_TCK);
+
+ delta_start *= 1000000000 / ticks_per_sec;
+ }
+ count->val = delta_start;
+ count->ena = count->run = delta_start;
+ count->lost = 0;
+ return 0;
+}
+
int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread)
{
- u64 read_format = evsel->core.attr.read_format;
+ if (evsel__is_tool(evsel))
+ return evsel__read_tool(evsel, cpu_map_idx, thread);
- if (read_format & PERF_FORMAT_GROUP)
+ if (evsel->core.attr.read_format & PERF_FORMAT_GROUP)
return evsel__read_group(evsel, cpu_map_idx, thread);
return evsel__read_one(evsel, cpu_map_idx, thread);
@@ -1829,6 +2003,14 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus,
perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0)
return -ENOMEM;
+ if ((evsel->tool_event == PERF_TOOL_SYSTEM_TIME ||
+ evsel->tool_event == PERF_TOOL_USER_TIME) &&
+ !evsel->start_times) {
+ evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), nthreads, sizeof(__u64));
+ if (!evsel->start_times)
+ return -ENOMEM;
+ }
+
evsel->open_flags = PERF_FLAG_FD_CLOEXEC;
if (evsel->cgrp)
evsel->open_flags |= PERF_FLAG_PID_CGROUP;
@@ -2011,6 +2193,13 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus,
int pid = -1, err, old_errno;
enum rlimit_action set_rlimit = NO_CHANGE;
+ if (evsel->tool_event == PERF_TOOL_DURATION_TIME) {
+ if (evsel->core.attr.sample_period) /* no sampling */
+ return -EINVAL;
+ evsel->start_time = rdclock();
+ return 0;
+ }
+
err = __evsel__prepare_open(evsel, cpus, threads);
if (err)
return err;
@@ -2043,6 +2232,46 @@ retry_open:
if (!evsel->cgrp && !evsel->core.system_wide)
pid = perf_thread_map__pid(threads, thread);
+ if (evsel->tool_event == PERF_TOOL_USER_TIME ||
+ evsel->tool_event == PERF_TOOL_SYSTEM_TIME) {
+ bool system = evsel->tool_event == PERF_TOOL_SYSTEM_TIME;
+ __u64 *start_time = NULL;
+
+ if (evsel->core.attr.sample_period) {
+ /* no sampling */
+ err = -EINVAL;
+ goto out_close;
+ }
+ if (pid > -1) {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+ fd = open(buf, O_RDONLY);
+ evsel->pid_stat = true;
+ } else {
+ fd = open("/proc/stat", O_RDONLY);
+ }
+ FD(evsel, idx, thread) = fd;
+ if (fd < 0) {
+ err = -errno;
+ goto out_close;
+ }
+ start_time = xyarray__entry(evsel->start_times, idx, thread);
+ if (pid > -1) {
+ err = read_pid_stat_field(fd, system ? 15 : 14,
+ start_time);
+ } else {
+ struct perf_cpu cpu;
+
+ cpu = perf_cpu_map__cpu(evsel->core.cpus, idx);
+ err = read_stat_field(fd, cpu, system ? 3 : 1,
+ start_time);
+ }
+ if (err)
+ goto out_close;
+ continue;
+ }
+
group_fd = get_group_fd(evsel, idx, thread);
if (group_fd == -2) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 375a38e15cd9..80b5f6dd868e 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -170,6 +170,20 @@ struct evsel {
/* for missing_features */
struct perf_pmu *pmu;
+
+ /* For tool events */
+ /* Beginning time subtracted when the counter is read. */
+ union {
+ /* duration_time is a single global time. */
+ __u64 start_time;
+ /*
+ * user_time and system_time read an initial value potentially
+ * per-CPU or per-pid.
+ */
+ struct xyarray *start_times;
+ };
+ /* Is the tool's fd for /proc/pid/stat or /proc/stat. */
+ bool pid_stat;
};
struct perf_missing_features {
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
index b8875aac8f87..b2536a59c44e 100644
--- a/tools/perf/util/expr.c
+++ b/tools/perf/util/expr.c
@@ -25,10 +25,6 @@
#include <math.h>
#include "pmu.h"
-#ifdef PARSER_DEBUG
-extern int expr_debug;
-#endif
-
struct expr_id_data {
union {
struct {
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
index ac17a3cb59dc..c8f6bee1fa61 100644
--- a/tools/perf/util/genelf.c
+++ b/tools/perf/util/genelf.c
@@ -54,11 +54,6 @@ typedef struct {
char name[0]; /* Start of the name+desc data */
} Elf_Note;
-struct options {
- char *output;
- int fd;
-};
-
static char shd_string_table[] = {
0,
'.', 't', 'e', 'x', 't', 0, /* 1 */
diff --git a/tools/perf/util/hisi-ptt-decoder/Build b/tools/perf/util/hisi-ptt-decoder/Build
index db3db8b75033..3298f7b7e308 100644
--- a/tools/perf/util/hisi-ptt-decoder/Build
+++ b/tools/perf/util/hisi-ptt-decoder/Build
@@ -1 +1 @@
-perf-$(CONFIG_AUXTRACE) += hisi-ptt-pkt-decoder.o
+perf-util-$(CONFIG_AUXTRACE) += hisi-ptt-pkt-decoder.o
diff --git a/tools/perf/util/hisi-ptt.c b/tools/perf/util/hisi-ptt.c
index 52d0ce302ca0..37ea987017f6 100644
--- a/tools/perf/util/hisi-ptt.c
+++ b/tools/perf/util/hisi-ptt.c
@@ -35,11 +35,6 @@ struct hisi_ptt {
u32 pmu_type;
};
-struct hisi_ptt_queue {
- struct hisi_ptt *ptt;
- struct auxtrace_buffer *buffer;
-};
-
static enum hisi_ptt_pkt_type hisi_ptt_check_packet_type(unsigned char *buf)
{
uint32_t head = *(uint32_t *)buf;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 2e9e193179dd..f028f113c4fd 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -2706,8 +2706,7 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
}
}
-size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp,
- bool skip_empty)
+size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp)
{
struct evsel *pos;
size_t ret = 0;
@@ -2715,7 +2714,8 @@ size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp,
evlist__for_each_entry(evlist, pos) {
struct hists *hists = evsel__hists(pos);
- if (skip_empty && !hists->stats.nr_samples && !hists->stats.nr_lost_samples)
+ if (symbol_conf.skip_empty && !hists->stats.nr_samples &&
+ !hists->stats.nr_lost_samples)
continue;
ret += fprintf(fp, "%s stats:\n", evsel__name(pos));
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8fb3bdd29188..5273f5c37050 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -375,8 +375,7 @@ void hists__inc_nr_lost_samples(struct hists *hists, u32 lost);
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, float min_pcnt, FILE *fp,
bool ignore_callchains);
-size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp,
- bool skip_empty);
+size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp);
void hists__filter_by_dso(struct hists *hists);
void hists__filter_by_thread(struct hists *hists);
diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build
index b41c2e9c6f88..30793d08c6d4 100644
--- a/tools/perf/util/intel-pt-decoder/Build
+++ b/tools/perf/util/intel-pt-decoder/Build
@@ -1,4 +1,4 @@
-perf-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o intel-pt-insn-decoder.o intel-pt-log.o intel-pt-decoder.o
+perf-util-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o intel-pt-insn-decoder.o intel-pt-log.o intel-pt-decoder.o
inat_tables_script = $(srctree)/tools/arch/x86/tools/gen-insn-attr-x86.awk
inat_tables_maps = $(srctree)/tools/arch/x86/lib/x86-opcode-map.txt
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
index c5d57027ec23..4407130d91f8 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
@@ -92,6 +92,15 @@ static void intel_pt_insn_decoder(struct insn *insn,
op = INTEL_PT_OP_JCC;
branch = INTEL_PT_BR_CONDITIONAL;
break;
+ case 0xa1:
+ if (insn_is_rex2(insn)) { /* jmpabs */
+ intel_pt_insn->op = INTEL_PT_OP_JMP;
+ /* jmpabs causes a TIP packet like an indirect branch */
+ intel_pt_insn->branch = INTEL_PT_BR_INDIRECT;
+ intel_pt_insn->length = insn->length;
+ return;
+ }
+ break;
case 0xc2: /* near ret */
case 0xc3: /* near ret */
case 0xca: /* far ret */
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index 16b39db594f4..432399cbe5dd 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -735,26 +735,79 @@ static unsigned int first_ending_after(struct maps *maps, const struct map *map)
return first;
}
+static int __maps__insert_sorted(struct maps *maps, unsigned int first_after_index,
+ struct map *new1, struct map *new2)
+{
+ struct map **maps_by_address = maps__maps_by_address(maps);
+ struct map **maps_by_name = maps__maps_by_name(maps);
+ unsigned int nr_maps = maps__nr_maps(maps);
+ unsigned int nr_allocate = RC_CHK_ACCESS(maps)->nr_maps_allocated;
+ unsigned int to_add = new2 ? 2 : 1;
+
+ assert(maps__maps_by_address_sorted(maps));
+ assert(first_after_index == nr_maps ||
+ map__end(new1) <= map__start(maps_by_address[first_after_index]));
+ assert(!new2 || map__end(new1) <= map__start(new2));
+ assert(first_after_index == nr_maps || !new2 ||
+ map__end(new2) <= map__start(maps_by_address[first_after_index]));
+
+ if (nr_maps + to_add > nr_allocate) {
+ nr_allocate = !nr_allocate ? 32 : nr_allocate * 2;
+
+ maps_by_address = realloc(maps_by_address, nr_allocate * sizeof(new1));
+ if (!maps_by_address)
+ return -ENOMEM;
+
+ maps__set_maps_by_address(maps, maps_by_address);
+ if (maps_by_name) {
+ maps_by_name = realloc(maps_by_name, nr_allocate * sizeof(new1));
+ if (!maps_by_name) {
+ /*
+ * If by name fails, just disable by name and it will
+ * recompute next time it is required.
+ */
+ __maps__free_maps_by_name(maps);
+ }
+ maps__set_maps_by_name(maps, maps_by_name);
+ }
+ RC_CHK_ACCESS(maps)->nr_maps_allocated = nr_allocate;
+ }
+ memmove(&maps_by_address[first_after_index+to_add],
+ &maps_by_address[first_after_index],
+ (nr_maps - first_after_index) * sizeof(new1));
+ maps_by_address[first_after_index] = map__get(new1);
+ if (maps_by_name)
+ maps_by_name[nr_maps] = map__get(new1);
+ if (new2) {
+ maps_by_address[first_after_index + 1] = map__get(new2);
+ if (maps_by_name)
+ maps_by_name[nr_maps + 1] = map__get(new2);
+ }
+ RC_CHK_ACCESS(maps)->nr_maps = nr_maps + to_add;
+ maps__set_maps_by_name_sorted(maps, false);
+ check_invariants(maps);
+ return 0;
+}
+
/*
* Adds new to maps, if new overlaps existing entries then the existing maps are
* adjusted or removed so that new fits without overlapping any entries.
*/
static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
{
- struct map **maps_by_address;
int err = 0;
FILE *fp = debug_file();
+ unsigned int i;
-sort_again:
if (!maps__maps_by_address_sorted(maps))
__maps__sort_by_address(maps);
- maps_by_address = maps__maps_by_address(maps);
/*
* Iterate through entries where the end of the existing entry is
* greater-than the new map's start.
*/
- for (unsigned int i = first_ending_after(maps, new); i < maps__nr_maps(maps); ) {
+ for (i = first_ending_after(maps, new); i < maps__nr_maps(maps); ) {
+ struct map **maps_by_address = maps__maps_by_address(maps);
struct map *pos = maps_by_address[i];
struct map *before = NULL, *after = NULL;
@@ -821,37 +874,55 @@ sort_again:
/* Maps are still ordered, go to next one. */
i++;
if (after) {
- __maps__insert(maps, after);
- map__put(after);
- if (!maps__maps_by_address_sorted(maps)) {
- /*
- * Sorting broken so invariants don't
- * hold, sort and go again.
- */
- goto sort_again;
- }
/*
- * Maps are still ordered, skip after and go to
- * next one (terminate loop).
+ * 'before' and 'after' mean 'new' split the
+ * 'pos' mapping and therefore there are no
+ * later mappings.
*/
- i++;
+ err = __maps__insert_sorted(maps, i, new, after);
+ map__put(after);
+ check_invariants(maps);
+ return err;
}
+ check_invariants(maps);
} else if (after) {
+ /*
+ * 'after' means 'new' split 'pos' and there are no
+ * later mappings.
+ */
map__put(maps_by_address[i]);
- maps_by_address[i] = after;
- /* Maps are ordered, go to next one. */
- i++;
+ maps_by_address[i] = map__get(new);
+ err = __maps__insert_sorted(maps, i + 1, after, NULL);
+ map__put(after);
+ check_invariants(maps);
+ return err;
} else {
+ struct map *next = NULL;
+
+ if (i + 1 < maps__nr_maps(maps))
+ next = maps_by_address[i + 1];
+
+ if (!next || map__start(next) >= map__end(new)) {
+ /*
+ * Replace existing mapping and end knowing
+ * there aren't later overlapping or any
+ * mappings.
+ */
+ map__put(maps_by_address[i]);
+ maps_by_address[i] = map__get(new);
+ check_invariants(maps);
+ return err;
+ }
__maps__remove(maps, pos);
+ check_invariants(maps);
/*
* Maps are ordered but no need to increase `i` as the
* later maps were moved down.
*/
}
- check_invariants(maps);
}
/* Add the map. */
- __maps__insert(maps, new);
+ err = __maps__insert_sorted(maps, i, new, NULL);
out_err:
return err;
}
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index 6dda47bb774f..be048bd02f36 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -8,6 +8,7 @@
#include <unistd.h>
#include <api/fs/fs.h>
#include <linux/kernel.h>
+#include "cpumap.h"
#include "map_symbol.h"
#include "mem-events.h"
#include "mem-info.h"
@@ -86,7 +87,7 @@ static const char *perf_pmu__mem_events_name(int i, struct perf_pmu *pmu)
return NULL;
e = &pmu->mem_events[i];
- if (!e)
+ if (!e || !e->name)
return NULL;
if (i == PERF_MEM_EVENTS__LOAD || i == PERF_MEM_EVENTS__LOAD_STORE) {
@@ -242,6 +243,7 @@ int perf_mem_events__record_args(const char **rec_argv, int *argv_nr)
int i = *argv_nr;
const char *s;
char *copy;
+ struct perf_cpu_map *cpu_map = NULL;
while ((pmu = perf_pmus__scan_mem(pmu)) != NULL) {
for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
@@ -266,7 +268,19 @@ int perf_mem_events__record_args(const char **rec_argv, int *argv_nr)
rec_argv[i++] = "-e";
rec_argv[i++] = copy;
+
+ cpu_map = perf_cpu_map__merge(cpu_map, pmu->cpus);
+ }
+ }
+
+ if (cpu_map) {
+ if (!perf_cpu_map__equal(cpu_map, cpu_map__online())) {
+ char buf[200];
+
+ cpu_map__snprint(cpu_map, buf, sizeof(buf));
+ pr_warning("Memory events are enabled on a subset of CPUs: %s\n", buf);
}
+ perf_cpu_map__put(cpu_map);
}
*argv_nr = i;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6ed0f9c5581d..321586fb5556 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -31,9 +31,6 @@
#define MAX_NAME_LEN 100
-#ifdef PARSER_DEBUG
-extern int parse_events_debug;
-#endif
static int get_config_terms(const struct parse_events_terms *head_config,
struct list_head *head_terms);
static int parse_events_terms__copy(const struct parse_events_terms *src,
@@ -308,11 +305,16 @@ static int add_event_tool(struct list_head *list, int *idx,
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_DUMMY,
};
+ const char *cpu_list = NULL;
+ if (tool_event == PERF_TOOL_DURATION_TIME) {
+ /* Duration time is gathered globally, pretend it is only on CPU0. */
+ cpu_list = "0";
+ }
evsel = __add_event(list, idx, &attr, /*init_attr=*/true, /*name=*/NULL,
/*metric_id=*/NULL, /*pmu=*/NULL,
/*config_terms=*/NULL, /*auto_merge_stats=*/false,
- /*cpu_list=*/"0");
+ cpu_list);
if (!evsel)
return -ENOMEM;
evsel->tool_event = tool_event;
diff --git a/tools/perf/util/perf-regs-arch/Build b/tools/perf/util/perf-regs-arch/Build
index d9d596d330a7..be95402aa540 100644
--- a/tools/perf/util/perf-regs-arch/Build
+++ b/tools/perf/util/perf-regs-arch/Build
@@ -1,9 +1,9 @@
-perf-y += perf_regs_aarch64.o
-perf-y += perf_regs_arm.o
-perf-y += perf_regs_csky.o
-perf-y += perf_regs_loongarch.o
-perf-y += perf_regs_mips.o
-perf-y += perf_regs_powerpc.o
-perf-y += perf_regs_riscv.o
-perf-y += perf_regs_s390.o
-perf-y += perf_regs_x86.o
+perf-util-y += perf_regs_aarch64.o
+perf-util-y += perf_regs_arm.o
+perf-util-y += perf_regs_csky.o
+perf-util-y += perf_regs_loongarch.o
+perf-util-y += perf_regs_mips.o
+perf-util-y += perf_regs_powerpc.o
+perf-util-y += perf_regs_riscv.o
+perf-util-y += perf_regs_s390.o
+perf-util-y += perf_regs_x86.o
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 888ce9912275..986166bc7c78 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -848,6 +848,23 @@ __weak const struct pmu_metrics_table *pmu_metrics_table__find(void)
}
/**
+ * Return the length of the PMU name not including the suffix for uncore PMUs.
+ *
+ * We want to deduplicate many similar uncore PMUs by stripping their suffixes,
+ * but there are never going to be too many core PMUs and the suffixes might be
+ * interesting. "arm_cortex_a53" vs "arm_cortex_a57" or "cpum_cf" for example.
+ *
+ * @skip_duplicate_pmus: False in verbose mode so all uncore PMUs are visible
+ */
+static size_t pmu_deduped_name_len(const struct perf_pmu *pmu, const char *name,
+ bool skip_duplicate_pmus)
+{
+ return skip_duplicate_pmus && !pmu->is_core
+ ? pmu_name_len_no_suffix(name)
+ : strlen(name);
+}
+
+/**
* perf_pmu__match_ignoring_suffix - Does the pmu_name match tok ignoring any
* trailing suffix? The Suffix must be in form
* tok_{digits}, or tok{digits}.
@@ -856,26 +873,34 @@ __weak const struct pmu_metrics_table *pmu_metrics_table__find(void)
*/
static bool perf_pmu__match_ignoring_suffix(const char *pmu_name, const char *tok)
{
- const char *p;
+ const char *p, *suffix;
+ bool has_hex = false;
if (strncmp(pmu_name, tok, strlen(tok)))
return false;
- p = pmu_name + strlen(tok);
+ suffix = p = pmu_name + strlen(tok);
if (*p == 0)
return true;
- if (*p == '_')
+ if (*p == '_') {
++p;
+ ++suffix;
+ }
/* Ensure we end in a number */
while (1) {
- if (!isdigit(*p))
+ if (!isxdigit(*p))
return false;
+ if (!has_hex)
+ has_hex = !isdigit(*p);
if (*(++p) == 0)
break;
}
+ if (has_hex)
+ return (p - suffix) > 2;
+
return true;
}
@@ -1765,7 +1790,7 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
size_t nr;
pmu_aliases_parse(pmu);
- nr = pmu->sysfs_aliases + pmu->sys_json_aliases;;
+ nr = pmu->sysfs_aliases + pmu->sys_json_aliases;
if (pmu->cpu_aliases_added)
nr += pmu->cpu_json_aliases;
@@ -1788,10 +1813,9 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
const struct perf_pmu_alias *alias, bool skip_duplicate_pmus)
{
struct parse_events_term *term;
- int pmu_name_len = skip_duplicate_pmus
- ? pmu_name_len_no_suffix(pmu->name, /*num=*/NULL)
- : (int)strlen(pmu->name);
- int used = snprintf(buf, len, "%.*s/%s", pmu_name_len, pmu->name, alias->name);
+ size_t pmu_name_len = pmu_deduped_name_len(pmu, pmu->name,
+ skip_duplicate_pmus);
+ int used = snprintf(buf, len, "%.*s/%s", (int)pmu_name_len, pmu->name, alias->name);
list_for_each_entry(term, &alias->terms.terms, list) {
if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
@@ -1828,13 +1852,11 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
pmu_aliases_parse(pmu);
pmu_add_cpu_aliases(pmu);
list_for_each_entry(event, &pmu->aliases, list) {
- size_t buf_used;
- int pmu_name_len;
+ size_t buf_used, pmu_name_len;
info.pmu_name = event->pmu_name ?: pmu->name;
- pmu_name_len = skip_duplicate_pmus
- ? pmu_name_len_no_suffix(info.pmu_name, /*num=*/NULL)
- : (int)strlen(info.pmu_name);
+ pmu_name_len = pmu_deduped_name_len(pmu, info.pmu_name,
+ skip_duplicate_pmus);
info.alias = NULL;
if (event->desc) {
info.name = event->name;
@@ -1859,7 +1881,7 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
info.encoding_desc = buf + buf_used;
parse_events_terms__to_strbuf(&event->terms, &sb);
buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used,
- "%.*s/%s/", pmu_name_len, info.pmu_name, sb.buf) + 1;
+ "%.*s/%s/", (int)pmu_name_len, info.pmu_name, sb.buf) + 1;
info.topic = event->topic;
info.str = sb.buf;
info.deprecated = event->deprecated;
@@ -2143,7 +2165,7 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
bool perf_pmu__match(const struct perf_pmu *pmu, const char *tok)
{
const char *name = pmu->name;
- bool need_fnmatch = strchr(tok, '*') != NULL;
+ bool need_fnmatch = strisglob(tok);
if (!strncmp(tok, "uncore_", 7))
tok += 7;
diff --git a/tools/perf/util/pmus.c b/tools/perf/util/pmus.c
index b9b4c5eb5002..3fcabfd8fca1 100644
--- a/tools/perf/util/pmus.c
+++ b/tools/perf/util/pmus.c
@@ -40,31 +40,52 @@ static bool read_sysfs_all_pmus;
static void pmu_read_sysfs(bool core_only);
-int pmu_name_len_no_suffix(const char *str, unsigned long *num)
+size_t pmu_name_len_no_suffix(const char *str)
{
int orig_len, len;
+ bool has_hex_digits = false;
orig_len = len = strlen(str);
- /* Non-uncore PMUs have their full length, for example, i915. */
- if (!strstarts(str, "uncore_"))
- return len;
-
- /*
- * Count trailing digits and '_', if '_{num}' suffix isn't present use
- * the full length.
- */
- while (len > 0 && isdigit(str[len - 1]))
+ /* Count trailing digits. */
+ while (len > 0 && isxdigit(str[len - 1])) {
+ if (!isdigit(str[len - 1]))
+ has_hex_digits = true;
len--;
+ }
if (len > 0 && len != orig_len && str[len - 1] == '_') {
- if (num)
- *num = strtoul(&str[len], NULL, 10);
- return len - 1;
+ /*
+ * There is a '_{num}' suffix. For decimal suffixes any length
+ * will do, for hexadecimal ensure more than 2 hex digits so
+ * that S390's cpum_cf PMU doesn't match.
+ */
+ if (!has_hex_digits || (orig_len - len) > 2)
+ return len - 1;
}
+ /* Use the full length. */
return orig_len;
}
+int pmu_name_cmp(const char *lhs_pmu_name, const char *rhs_pmu_name)
+{
+ unsigned long lhs_num = 0, rhs_num = 0;
+ size_t lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name);
+ size_t rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name);
+ int ret = strncmp(lhs_pmu_name, rhs_pmu_name,
+ lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len);
+
+ if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0)
+ return ret;
+
+ if (lhs_pmu_name_len + 1 < strlen(lhs_pmu_name))
+ lhs_num = strtoul(&lhs_pmu_name[lhs_pmu_name_len + 1], NULL, 16);
+ if (rhs_pmu_name_len + 1 < strlen(rhs_pmu_name))
+ rhs_num = strtoul(&rhs_pmu_name[rhs_pmu_name_len + 1], NULL, 16);
+
+ return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0);
+}
+
void perf_pmus__destroy(void)
{
struct perf_pmu *pmu, *tmp;
@@ -167,20 +188,10 @@ static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
static int pmus_cmp(void *priv __maybe_unused,
const struct list_head *lhs, const struct list_head *rhs)
{
- unsigned long lhs_num = 0, rhs_num = 0;
struct perf_pmu *lhs_pmu = container_of(lhs, struct perf_pmu, list);
struct perf_pmu *rhs_pmu = container_of(rhs, struct perf_pmu, list);
- const char *lhs_pmu_name = lhs_pmu->name ?: "";
- const char *rhs_pmu_name = rhs_pmu->name ?: "";
- int lhs_pmu_name_len = pmu_name_len_no_suffix(lhs_pmu_name, &lhs_num);
- int rhs_pmu_name_len = pmu_name_len_no_suffix(rhs_pmu_name, &rhs_num);
- int ret = strncmp(lhs_pmu_name, rhs_pmu_name,
- lhs_pmu_name_len < rhs_pmu_name_len ? lhs_pmu_name_len : rhs_pmu_name_len);
-
- if (lhs_pmu_name_len != rhs_pmu_name_len || ret != 0 || lhs_pmu_name_len == 0)
- return ret;
- return lhs_num < rhs_num ? -1 : (lhs_num > rhs_num ? 1 : 0);
+ return pmu_name_cmp(lhs_pmu->name ?: "", rhs_pmu->name ?: "");
}
/* Add all pmus in sysfs to pmu list: */
@@ -300,11 +311,11 @@ static struct perf_pmu *perf_pmus__scan_skip_duplicates(struct perf_pmu *pmu)
pmu_read_sysfs(/*core_only=*/false);
pmu = list_prepare_entry(pmu, &core_pmus, list);
} else
- last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", NULL);
+ last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");
if (use_core_pmus) {
list_for_each_entry_continue(pmu, &core_pmus, list) {
- int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", /*num=*/NULL);
+ int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");
if (last_pmu_name_len == pmu_name_len &&
!strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len))
@@ -316,7 +327,7 @@ static struct perf_pmu *perf_pmus__scan_skip_duplicates(struct perf_pmu *pmu)
pmu = list_prepare_entry(pmu, &other_pmus, list);
}
list_for_each_entry_continue(pmu, &other_pmus, list) {
- int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "", /*num=*/NULL);
+ int pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");
if (last_pmu_name_len == pmu_name_len &&
!strncmp(last_pmu_name, pmu->name ?: "", pmu_name_len))
@@ -477,8 +488,8 @@ void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *p
qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
for (int j = 0; j < len; j++) {
/* Skip duplicates */
- if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
- continue;
+ if (j < len - 1 && pmu_alias_is_duplicate(&aliases[j], &aliases[j + 1]))
+ goto free;
print_cb->print_event(print_state,
aliases[j].pmu_name,
@@ -491,6 +502,7 @@ void perf_pmus__print_pmu_events(const struct print_callbacks *print_cb, void *p
aliases[j].desc,
aliases[j].long_desc,
aliases[j].encoding_desc);
+free:
zfree(&aliases[j].name);
zfree(&aliases[j].alias);
zfree(&aliases[j].scale_unit);
@@ -566,7 +578,7 @@ void perf_pmus__print_raw_pmu_events(const struct print_callbacks *print_cb, voi
.long_string = STRBUF_INIT,
.num_formats = 0,
};
- int len = pmu_name_len_no_suffix(pmu->name, /*num=*/NULL);
+ int len = pmu_name_len_no_suffix(pmu->name);
const char *desc = "(see 'man perf-list' or 'man perf-record' on how to encode it)";
if (!pmu->is_core)
diff --git a/tools/perf/util/pmus.h b/tools/perf/util/pmus.h
index 9d4ded80b8e9..bdbff02324bb 100644
--- a/tools/perf/util/pmus.h
+++ b/tools/perf/util/pmus.h
@@ -2,10 +2,15 @@
#ifndef __PMUS_H
#define __PMUS_H
+#include <stdbool.h>
+#include <stddef.h>
+
struct perf_pmu;
struct print_callbacks;
-int pmu_name_len_no_suffix(const char *str, unsigned long *num);
+size_t pmu_name_len_no_suffix(const char *str);
+/* Exposed for testing only. */
+int pmu_name_cmp(const char *lhs_pmu_name, const char *rhs_pmu_name);
void perf_pmus__destroy(void);
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
deleted file mode 100644
index 1bec945f4838..000000000000
--- a/tools/perf/util/python-ext-sources
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# List of files needed by perf python extension
-#
-# Each source file must be placed on its own line so that it can be
-# processed by Makefile and util/setup.py accordingly.
-#
-
-util/python.c
-../lib/ctype.c
-util/cap.c
-util/evlist.c
-util/evsel.c
-util/evsel_fprintf.c
-util/perf_event_attr_fprintf.c
-util/cpumap.c
-util/memswap.c
-util/mmap.c
-util/namespaces.c
-../lib/bitmap.c
-../lib/find_bit.c
-../lib/list_sort.c
-../lib/hweight.c
-../lib/string.c
-../lib/vsprintf.c
-util/thread_map.c
-util/util.c
-util/cgroup.c
-util/parse-branch-options.c
-util/rblist.c
-util/counts.c
-util/print_binary.c
-util/strlist.c
-util/trace-event.c
-util/trace-event-parse.c
-../lib/rbtree.c
-util/string.c
-util/symbol_fprintf.c
-util/units.c
-util/affinity.c
-util/rwsem.c
-util/hashmap.c
-util/perf_regs.c
-util/fncache.c
-util/rlimit.c
-util/perf-regs-arch/perf_regs_aarch64.c
-util/perf-regs-arch/perf_regs_arm.c
-util/perf-regs-arch/perf_regs_csky.c
-util/perf-regs-arch/perf_regs_loongarch.c
-util/perf-regs-arch/perf_regs_mips.c
-util/perf-regs-arch/perf_regs_powerpc.c
-util/perf-regs-arch/perf_regs_riscv.c
-util/perf-regs-arch/perf_regs_s390.c
-util/perf-regs-arch/perf_regs_x86.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 0aeb97c11c03..3be882b2e845 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -10,21 +10,19 @@
#endif
#include <perf/mmap.h>
#include "evlist.h"
-#include "callchain.h"
#include "evsel.h"
#include "event.h"
#include "print_binary.h"
#include "thread_map.h"
#include "trace-event.h"
#include "mmap.h"
-#include "stat.h"
-#include "metricgroup.h"
#include "util/bpf-filter.h"
#include "util/env.h"
-#include "util/pmu.h"
-#include "util/pmus.h"
+#include "util/kvm-stat.h"
+#include "util/kwork.h"
+#include "util/lock-contention.h"
#include <internal/lib.h>
-#include "util.h"
+#include "../builtin.h"
#if PY_MAJOR_VERSION < 3
#define _PyUnicode_FromString(arg) \
@@ -50,166 +48,6 @@
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#endif
-/*
- * Avoid bringing in event parsing.
- */
-int parse_event(struct evlist *evlist __maybe_unused, const char *str __maybe_unused)
-{
- return 0;
-}
-
-/*
- * Provide these two so that we don't have to link against callchain.c and
- * start dragging hist.c, etc.
- */
-struct callchain_param callchain_param;
-
-int parse_callchain_record(const char *arg __maybe_unused,
- struct callchain_param *param __maybe_unused)
-{
- return 0;
-}
-
-/*
- * Add these not to drag util/env.c
- */
-struct perf_env perf_env;
-
-const char *perf_env__cpuid(struct perf_env *env __maybe_unused)
-{
- return NULL;
-}
-
-// This one is a bit easier, wouldn't drag too much, but leave it as a stub we need it here
-const char *perf_env__arch(struct perf_env *env __maybe_unused)
-{
- return NULL;
-}
-
-/*
- * These ones are needed not to drag the PMU bandwagon, jevents generated
- * pmu_sys_event_tables, etc and evsel__find_pmu() is used so far just for
- * doing per PMU perf_event_attr.exclude_guest handling, not really needed, so
- * far, for the perf python binding known usecases, revisit if this become
- * necessary.
- */
-struct perf_pmu *evsel__find_pmu(const struct evsel *evsel __maybe_unused)
-{
- return NULL;
-}
-
-int perf_pmu__scan_file(const struct perf_pmu *pmu, const char *name, const char *fmt, ...)
-{
- return EOF;
-}
-
-const char *perf_pmu__name_from_config(struct perf_pmu *pmu __maybe_unused, u64 config __maybe_unused)
-{
- return NULL;
-}
-
-struct perf_pmu *perf_pmus__find_by_type(unsigned int type __maybe_unused)
-{
- return NULL;
-}
-
-int perf_pmus__num_core_pmus(void)
-{
- return 1;
-}
-
-bool evsel__is_aux_event(const struct evsel *evsel __maybe_unused)
-{
- return false;
-}
-
-bool perf_pmus__supports_extended_type(void)
-{
- return false;
-}
-
-/*
- * Add this one here not to drag util/metricgroup.c
- */
-int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
- struct rblist *new_metric_events,
- struct rblist *old_metric_events)
-{
- return 0;
-}
-
-/*
- * Add this one here not to drag util/trace-event-info.c
- */
-char *tracepoint_id_to_name(u64 config)
-{
- return NULL;
-}
-
-/*
- * XXX: All these evsel destructors need some better mechanism, like a linked
- * list of destructors registered when the relevant code indeed is used instead
- * of having more and more calls in perf_evsel__delete(). -- acme
- *
- * For now, add some more:
- *
- * Not to drag the BPF bandwagon...
- */
-void bpf_counter__destroy(struct evsel *evsel);
-int bpf_counter__install_pe(struct evsel *evsel, int cpu, int fd);
-int bpf_counter__disable(struct evsel *evsel);
-
-void bpf_counter__destroy(struct evsel *evsel __maybe_unused)
-{
-}
-
-int bpf_counter__install_pe(struct evsel *evsel __maybe_unused, int cpu __maybe_unused, int fd __maybe_unused)
-{
- return 0;
-}
-
-int bpf_counter__disable(struct evsel *evsel __maybe_unused)
-{
- return 0;
-}
-
-// not to drag util/bpf-filter.c
-#ifdef HAVE_BPF_SKEL
-int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused)
-{
- return 0;
-}
-
-int perf_bpf_filter__destroy(struct evsel *evsel __maybe_unused)
-{
- return 0;
-}
-#endif
-
-/*
- * Support debug printing even though util/debug.c is not linked. That means
- * implementing 'verbose' and 'eprintf'.
- */
-int verbose;
-int debug_kmaps;
-int debug_peo_args;
-
-int eprintf(int level, int var, const char *fmt, ...);
-
-int eprintf(int level, int var, const char *fmt, ...)
-{
- va_list args;
- int ret = 0;
-
- if (var >= level) {
- va_start(args, fmt);
- ret = vfprintf(stderr, fmt, args);
- va_end(args);
- }
-
- return ret;
-}
-
/* Define PyVarObject_HEAD_INIT for python 2.5 */
#ifndef PyVarObject_HEAD_INIT
# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
@@ -1510,15 +1348,102 @@ error:
#endif
}
-/*
- * Dummy, to avoid dragging all the test_attr infrastructure in the python
- * binding.
- */
-void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu,
- int fd, int group_fd, unsigned long flags)
+
+/* The following are stubs to avoid dragging in builtin-* objects. */
+/* TODO: move the code out of the builtin-* file into util. */
+
+unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
+
+bool kvm_entry_event(struct evsel *evsel __maybe_unused)
{
+ return false;
+}
+
+bool kvm_exit_event(struct evsel *evsel __maybe_unused)
+{
+ return false;
+}
+
+bool exit_event_begin(struct evsel *evsel __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ struct event_key *key __maybe_unused)
+{
+ return false;
+}
+
+bool exit_event_end(struct evsel *evsel __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ struct event_key *key __maybe_unused)
+{
+ return false;
+}
+
+void exit_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
+ struct event_key *key __maybe_unused,
+ char *decode __maybe_unused)
+{
+}
+
+int find_scripts(char **scripts_array __maybe_unused, char **scripts_path_array __maybe_unused,
+ int num __maybe_unused, int pathlen __maybe_unused)
+{
+ return -1;
+}
+
+void perf_stat__set_no_csv_summary(int set __maybe_unused)
+{
+}
+
+void perf_stat__set_big_num(int set __maybe_unused)
+{
+}
+
+int script_spec_register(const char *spec __maybe_unused, struct scripting_ops *ops __maybe_unused)
+{
+ return -1;
+}
+
+arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch __maybe_unused)
+{
+ return NULL;
+}
+
+struct kwork_work *perf_kwork_add_work(struct perf_kwork *kwork __maybe_unused,
+ struct kwork_class *class __maybe_unused,
+ struct kwork_work *key __maybe_unused)
+{
+ return NULL;
+}
+
+void script_fetch_insn(struct perf_sample *sample __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+}
+
+int perf_sample__sprintf_flags(u32 flags __maybe_unused, char *str __maybe_unused,
+ size_t sz __maybe_unused)
+{
+ return -1;
+}
+
+bool match_callstack_filter(struct machine *machine __maybe_unused, u64 *callstack __maybe_unused)
+{
+ return false;
+}
+
+struct lock_stat *lock_stat_find(u64 addr __maybe_unused)
+{
+ return NULL;
+}
+
+struct lock_stat *lock_stat_findnew(u64 addr __maybe_unused, const char *name __maybe_unused,
+ int flags __maybe_unused)
+{
+ return NULL;
}
-void evlist__free_stats(struct evlist *evlist)
+int cmd_inject(int argc __maybe_unused, const char *argv[] __maybe_unused)
{
+ return -1;
}
diff --git a/tools/perf/util/scripting-engines/Build b/tools/perf/util/scripting-engines/Build
index 586b94e90f4e..2282fe3772f3 100644
--- a/tools/perf/util/scripting-engines/Build
+++ b/tools/perf/util/scripting-engines/Build
@@ -1,7 +1,7 @@
ifeq ($(CONFIG_LIBTRACEEVENT),y)
- perf-$(CONFIG_LIBPERL) += trace-event-perl.o
+ perf-util-$(CONFIG_LIBPERL) += trace-event-perl.o
endif
-perf-$(CONFIG_LIBPYTHON) += trace-event-python.o
+perf-util-$(CONFIG_LIBPYTHON) += trace-event-python.o
CFLAGS_trace-event-perl.o += $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-nested-externs -Wno-undef -Wno-switch-default -Wno-bad-function-cast -Wno-declaration-after-statement -Wno-switch-enum
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index a10343b9dcd4..5596bed1b8c8 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -2050,6 +2050,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
{
struct ordered_events *oe = &session->ordered_events;
struct perf_tool *tool = session->tool;
+ struct ui_progress prog;
union perf_event *event;
uint32_t size, cur_size = 0;
void *buf = NULL;
@@ -2057,9 +2058,21 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
u64 head;
ssize_t err;
void *p;
+ bool update_prog = false;
perf_tool__fill_defaults(tool);
+ /*
+ * If it's from a file saving pipe data (by redirection), it would have
+ * a file name other than "-". Then we can get the total size and show
+ * the progress.
+ */
+ if (strcmp(session->data->path, "-") && session->data->file.size) {
+ ui_progress__init_size(&prog, session->data->file.size,
+ "Processing events...");
+ update_prog = true;
+ }
+
head = 0;
cur_size = sizeof(union perf_event);
@@ -2131,6 +2144,9 @@ more:
if (err)
goto out_err;
+ if (update_prog)
+ ui_progress__update(&prog, size);
+
if (!session_done())
goto more;
done:
@@ -2144,6 +2160,8 @@ done:
err = perf_session__flush_thread_stacks(session);
out_err:
free(buf);
+ if (update_prog)
+ ui_progress__finish();
if (!tool->no_warn)
perf_session__warn_about_errors(session);
ordered_events__free(&session->ordered_events);
@@ -2523,7 +2541,7 @@ static int __perf_session__process_dir_events(struct perf_session *session)
perf_tool__fill_defaults(tool);
- ui_progress__init_size(&prog, total_size, "Sorting events...");
+ ui_progress__init_size(&prog, total_size, "Processing events...");
nr_readers = 1;
for (i = 0; i < data->dir.nr; i++) {
@@ -2696,8 +2714,7 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp
return machines__fprintf_dsos_buildid(&session->machines, fp, skip, parm);
}
-size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp,
- bool skip_empty)
+size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
{
size_t ret;
const char *msg = "";
@@ -2707,7 +2724,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp,
ret = fprintf(fp, "\nAggregated stats:%s\n", msg);
- ret += events_stats__fprintf(&session->evlist->stats, fp, skip_empty);
+ ret += events_stats__fprintf(&session->evlist->stats, fp);
return ret;
}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3b0256e977a6..4c29dc86956f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -130,8 +130,7 @@ size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp);
size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
bool (fn)(struct dso *dso, int parm), int parm);
-size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp,
- bool skip_empty);
+size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
void perf_session__dump_kmaps(struct perf_session *session);
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 3107f5aa8c9a..142e9d447ce7 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -60,7 +60,7 @@ class install_lib(_install_lib):
cflags = getenv('CFLAGS', '').split()
# switch off several checks (need to be at the end of cflags list)
-cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls', '-DPYTHON_PERF' ]
+cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ]
if cc_is_clang:
cflags += ["-Wno-unused-command-line-argument" ]
else:
@@ -72,36 +72,11 @@ cflags += [ "-Wno-declaration-after-statement" ]
src_perf = getenv('srctree') + '/tools/perf'
build_lib = getenv('PYTHON_EXTBUILD_LIB')
build_tmp = getenv('PYTHON_EXTBUILD_TMP')
-libtraceevent = getenv('LIBTRACEEVENT')
-libapikfs = getenv('LIBAPI')
-libperf = getenv('LIBPERF')
-
-ext_sources = [f.strip() for f in open('util/python-ext-sources')
- if len(f.strip()) > 0 and f[0] != '#']
-
-extra_libraries = []
-
-if '-DHAVE_LIBTRACEEVENT' in cflags:
- extra_libraries += [ 'traceevent' ]
-else:
- ext_sources.remove('util/trace-event.c')
- ext_sources.remove('util/trace-event-parse.c')
-
-# use full paths with source files
-ext_sources = list(map(lambda x: '%s/%s' % (src_perf, x) , ext_sources))
-
-if '-DHAVE_LIBNUMA_SUPPORT' in cflags:
- extra_libraries += [ 'numa' ]
-if '-DHAVE_LIBCAP_SUPPORT' in cflags:
- extra_libraries += [ 'cap' ]
perf = Extension('perf',
- sources = ext_sources,
- include_dirs = ['util/include'],
- libraries = extra_libraries,
- extra_compile_args = cflags,
- extra_objects = [ x for x in [libtraceevent, libapikfs, libperf]
- if x is not None],
+ sources = [ src_perf + '/util/python.c' ],
+ include_dirs = ['util/include'],
+ extra_compile_args = cflags,
)
setup(name='perf',
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cd39ea972193..ab7c7ff35f9b 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -334,7 +334,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
* comparing symbol address alone is not enough since it's a
* relative address within a dso.
*/
- if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) {
+ if (!hists__has(left->hists, dso)) {
ret = sort__dso_cmp(left, right);
if (ret != 0)
return ret;
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 9d670d8c1c08..760742fd4a7d 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -39,7 +39,7 @@ static const char *srcline_dso_name(struct dso *dso)
if (dso_name[0] == '[')
return NULL;
- if (!strncmp(dso_name, "/tmp/perf-", 10))
+ if (is_perf_pid_map_name(dso_name))
return NULL;
return dso_name;
@@ -288,7 +288,7 @@ static int inline_list__append_dso_a2l(struct dso *dso,
struct inline_node *node,
struct symbol *sym)
{
- struct a2l_data *a2l = dso->a2l;
+ struct a2l_data *a2l = dso__a2l(dso);
struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname);
char *srcline = NULL;
@@ -304,11 +304,11 @@ static int addr2line(const char *dso_name, u64 addr,
struct symbol *sym)
{
int ret = 0;
- struct a2l_data *a2l = dso->a2l;
+ struct a2l_data *a2l = dso__a2l(dso);
if (!a2l) {
- dso->a2l = addr2line_init(dso_name);
- a2l = dso->a2l;
+ a2l = addr2line_init(dso_name);
+ dso__set_a2l(dso, a2l);
}
if (a2l == NULL) {
@@ -360,14 +360,14 @@ static int addr2line(const char *dso_name, u64 addr,
void dso__free_a2l(struct dso *dso)
{
- struct a2l_data *a2l = dso->a2l;
+ struct a2l_data *a2l = dso__a2l(dso);
if (!a2l)
return;
addr2line_cleanup(a2l);
- dso->a2l = NULL;
+ dso__set_a2l(dso, NULL);
}
#else /* HAVE_LIBBFD_SUPPORT */
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index 91d2f7f65df7..c38bcb6f4c78 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -38,6 +38,7 @@
static int aggr_header_lens[] = {
[AGGR_CORE] = 18,
[AGGR_CACHE] = 22,
+ [AGGR_CLUSTER] = 20,
[AGGR_DIE] = 12,
[AGGR_SOCKET] = 6,
[AGGR_NODE] = 6,
@@ -49,6 +50,7 @@ static int aggr_header_lens[] = {
static const char *aggr_header_csv[] = {
[AGGR_CORE] = "core,cpus,",
[AGGR_CACHE] = "cache,cpus,",
+ [AGGR_CLUSTER] = "cluster,cpus,",
[AGGR_DIE] = "die,cpus,",
[AGGR_SOCKET] = "socket,cpus,",
[AGGR_NONE] = "cpu,",
@@ -60,6 +62,7 @@ static const char *aggr_header_csv[] = {
static const char *aggr_header_std[] = {
[AGGR_CORE] = "core",
[AGGR_CACHE] = "cache",
+ [AGGR_CLUSTER] = "cluster",
[AGGR_DIE] = "die",
[AGGR_SOCKET] = "socket",
[AGGR_NONE] = "cpu",
@@ -1183,10 +1186,21 @@ static void print_metric_headers_std(struct perf_stat_config *config,
static void print_metric_headers_csv(struct perf_stat_config *config,
bool no_indent __maybe_unused)
{
+ const char *p;
+
if (config->interval)
- fputs("time,", config->output);
- if (!config->iostat_run)
- fputs(aggr_header_csv[config->aggr_mode], config->output);
+ fprintf(config->output, "time%s", config->csv_sep);
+ if (config->iostat_run)
+ return;
+
+ p = aggr_header_csv[config->aggr_mode];
+ while (*p) {
+ if (*p == ',')
+ fputs(config->csv_sep, config->output);
+ else
+ fputc(*p, config->output);
+ p++;
+ }
}
static void print_metric_headers_json(struct perf_stat_config *config __maybe_unused,
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 3466aa952442..6bb975e46de3 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -176,6 +176,13 @@ static double find_stat(const struct evsel *evsel, int aggr_idx, enum stat_type
if (type != evsel__stat_type(cur))
continue;
+ /*
+ * Except the SW CLOCK events,
+ * ignore if not the PMU we're looking for.
+ */
+ if ((type != STAT_NSECS) && (evsel->pmu != cur->pmu))
+ continue;
+
aggr = &cur->stats->aggr[aggr_idx];
if (type == STAT_NSECS)
return aggr->counts.val;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 9e5940b5bc59..19eb623e0826 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1607,7 +1607,7 @@ int dso__load_bfd_symbols(struct dso *dso, const char *debugfile)
if (!bfd_check_format(abfd, bfd_object)) {
pr_debug2("%s: cannot read %s bfd file.\n", __func__,
- dso->long_name);
+ dso__long_name(dso));
goto out_close;
}
@@ -1640,12 +1640,13 @@ int dso__load_bfd_symbols(struct dso *dso, const char *debugfile)
}
if (i < symbols_count) {
/* PE symbols can only have 4 bytes, so use .text high bits */
- dso->text_offset = section->vma - (u32)section->vma;
- dso->text_offset += (u32)bfd_asymbol_value(symbols[i]);
- dso->text_end = (section->vma - dso->text_offset) + section->size;
+ u64 text_offset = (section->vma - (u32)section->vma)
+ + (u32)bfd_asymbol_value(symbols[i]);
+ dso__set_text_offset(dso, text_offset);
+ dso__set_text_end(dso, (section->vma - text_offset) + section->size);
} else {
- dso->text_offset = section->vma - section->filepos;
- dso->text_end = section->filepos + section->size;
+ dso__set_text_offset(dso, section->vma - section->filepos);
+ dso__set_text_end(dso, section->filepos + section->size);
}
}
@@ -1671,7 +1672,7 @@ int dso__load_bfd_symbols(struct dso *dso, const char *debugfile)
else
len = section->size - sym->value;
- start = bfd_asymbol_value(sym) - dso->text_offset;
+ start = bfd_asymbol_value(sym) - dso__text_offset(dso);
symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC,
bfd_asymbol_name(sym));
if (!symbol)
@@ -1799,7 +1800,8 @@ int dso__load(struct dso *dso, struct map *map)
const char *map_path = dso__long_name(dso);
mutex_lock(dso__lock(dso));
- perfmap = strncmp(dso__name(dso), "/tmp/perf-", 10) == 0;
+ perfmap = is_perf_pid_map_name(map_path);
+
if (perfmap) {
if (dso__nsinfo(dso) &&
(dso__find_perf_map(newmapname, sizeof(newmapname),
@@ -1816,10 +1818,7 @@ int dso__load(struct dso *dso, struct map *map)
goto out;
}
- kmod = dso__symtab_type(dso) == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
- dso__symtab_type(dso) == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
- dso__symtab_type(dso) == DSO_BINARY_TYPE__GUEST_KMODULE ||
- dso__symtab_type(dso) == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+ kmod = dso__is_kmod(dso);
if (dso__kernel(dso) && !kmod) {
if (dso__kernel(dso) == DSO_SPACE__KERNEL)
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index c114bbceef40..657cfa5af43c 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -46,7 +46,8 @@ struct symbol_conf {
lazy_load_kernel_maps,
keep_exited_threads,
annotate_data_member,
- annotate_data_sample;
+ annotate_data_sample,
+ skip_empty;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c
index 63be7b58761d..0dd26b991b3f 100644
--- a/tools/perf/util/syscalltbl.c
+++ b/tools/perf/util/syscalltbl.c
@@ -123,6 +123,13 @@ int syscalltbl__id(struct syscalltbl *tbl, const char *name)
return sc ? sc->id : -1;
}
+int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx)
+{
+ struct syscall *syscalls = tbl->syscalls.entries;
+
+ return idx < tbl->syscalls.nr_entries ? syscalls[idx].id : -1;
+}
+
int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
{
int i;
diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h
index a41d2ca9e4ae..2b53b7ed25a6 100644
--- a/tools/perf/util/syscalltbl.h
+++ b/tools/perf/util/syscalltbl.h
@@ -16,6 +16,7 @@ void syscalltbl__delete(struct syscalltbl *tbl);
const char *syscalltbl__name(const struct syscalltbl *tbl, int id);
int syscalltbl__id(struct syscalltbl *tbl, const char *name);
+int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx);
int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx);
int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx);
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index b38d322734b4..bde216e630d2 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -29,8 +29,8 @@ static int __find_debuginfo(Dwfl_Module *mod __maybe_unused, void **userdata,
const struct dso *dso = *userdata;
assert(dso);
- if (dso->symsrc_filename && strcmp (file_name, dso->symsrc_filename))
- *debuginfo_file_name = strdup(dso->symsrc_filename);
+ if (dso__symsrc_filename(dso) && strcmp(file_name, dso__symsrc_filename(dso)))
+ *debuginfo_file_name = strdup(dso__symsrc_filename(dso));
return -1;
}
@@ -66,7 +66,7 @@ static int __report_module(struct addr_location *al, u64 ip,
* a different code in another DSO. So just use the map->start
* directly to pick the correct one.
*/
- if (!strncmp(dso->long_name, "/tmp/jitted-", 12))
+ if (!strncmp(dso__long_name(dso), "/tmp/jitted-", 12))
base = map__start(al->map);
else
base = map__start(al->map) - map__pgoff(al->map);
@@ -83,15 +83,15 @@ static int __report_module(struct addr_location *al, u64 ip,
if (!mod) {
char filename[PATH_MAX];
- __symbol__join_symfs(filename, sizeof(filename), dso->long_name);
- mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
+ __symbol__join_symfs(filename, sizeof(filename), dso__long_name(dso));
+ mod = dwfl_report_elf(ui->dwfl, dso__short_name(dso), filename, -1,
base, false);
}
if (!mod) {
char filename[PATH_MAX];
if (dso__build_id_filename(dso, filename, sizeof(filename), false))
- mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
+ mod = dwfl_report_elf(ui->dwfl, dso__short_name(dso), filename, -1,
base, false);
}
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index cde267ea3e99..f6a6f6a91030 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -363,7 +363,7 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
struct machine *machine, u64 *offset)
{
int fd;
- u64 ofs = dso->data.debug_frame_offset;
+ u64 ofs = dso__data(dso)->debug_frame_offset;
/* debug_frame can reside in:
* - dso
@@ -379,7 +379,7 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
}
if (ofs <= 0) {
- fd = open(dso->symsrc_filename, O_RDONLY);
+ fd = open(dso__symsrc_filename(dso), O_RDONLY);
if (fd >= 0) {
ofs = elf_section_offset(fd, ".debug_frame");
close(fd);
@@ -390,6 +390,11 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
char *debuglink = malloc(PATH_MAX);
int ret = 0;
+ if (debuglink == NULL) {
+ pr_err("unwind: Can't read unwind spec debug frame.\n");
+ return -ENOMEM;
+ }
+
ret = dso__read_binary_type_filename(
dso, DSO_BINARY_TYPE__DEBUGLINK,
machine->root_dir, debuglink, PATH_MAX);
@@ -402,21 +407,21 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
}
}
if (ofs > 0) {
- if (dso->symsrc_filename != NULL) {
+ if (dso__symsrc_filename(dso) != NULL) {
pr_warning(
"%s: overwrite symsrc(%s,%s)\n",
__func__,
- dso->symsrc_filename,
+ dso__symsrc_filename(dso),
debuglink);
- zfree(&dso->symsrc_filename);
+ zfree(&dso__symsrc_filename(dso));
}
- dso->symsrc_filename = debuglink;
+ dso__set_symsrc_filename(dso, debuglink);
} else {
free(debuglink);
}
}
- dso->data.debug_frame_offset = ofs;
+ dso__data(dso)->debug_frame_offset = ofs;
}
*offset = ofs;
@@ -481,7 +486,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
if (ret < 0 &&
!read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) {
int fd = dso__data_get_fd(dso, ui->machine);
- int is_exec = elf_is_exec(fd, dso->name);
+ int is_exec = elf_is_exec(fd, dso__name(dso));
u64 start = map__start(map);
unw_word_t base = is_exec ? 0 : start;
const char *symfile;
@@ -489,7 +494,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
if (fd >= 0)
dso__data_put_fd(dso);
- symfile = dso->symsrc_filename ?: dso->name;
+ symfile = dso__symsrc_filename(dso) ?: dso__name(dso);
memset(&di, 0, sizeof(di));
if (dwarf_find_debug_frame(0, &di, ip, base, symfile, start, map__end(map)))