perf tools changes for v7.0:

- Introduce 'perf sched stats' tool with record/report/diff workflows
   using schedstat counters.
 
 - Add a faster libdw based addr2line implementation and allow selecting
   it or its alternatives via 'perf config addr2line.style='.
 
 - Data-type profiling fixes and improvements including the ability
   to select fields using 'perf report''s -F/-fields, e.g.:
 
     'perf report --fields overhead,type'
 
 - Add 'perf test' regression tests for Data-type profiling with
   C and Rust workloads.
 
 - Fix srcline printing with inlines in callchains, make sure this has
   coverage in 'perf test'.
 
 - Fix printing of leaf IP in LBR callchains.
 
 - Fix display of metrics without sufficient permission in 'perf stat'.
 
 - Print all machines in 'perf kvm report -vvv', not just the host.
 
 - Switch from SHA-1 to BLAKE2s for build ID generation, remove SHA-1
   code.
 
 - Fix 'perf report's histogram entry collapsing with '-F' option.
 
 - Use system's cacheline size instead of a hardcoded value in 'perf
   report'.
 
 - Allow filtering conversion by time range in 'perf data'.
 
 - Cover conversion to CTF using 'perf data' in 'perf test'.
 
 - Address newer glibc const-correctness (-Werror=discarded-qualifiers)
   issues.
 
 - Fixes and improvements for ARM's CoreSight support, simplify ARM SPE
   event config in 'perf mem', update docs for 'perf c2c' including the
   ARM events it can be used with.
 
 - Build support for generating metrics from arch specific python script,
   add extra AMD, Intel, ARM64 metrics using it.
 
 - Add AMD Zen 6 events and metrics.
 
 - Add JSON file with OpenHW Risc-V CVA6 hardware counters.
 
 - Add 'perf kvm' stats live testing.
 
 - Add more 'perf stat' tests to 'perf test'.
 
 - Fix segfault in `perf lock contention -b/--use-bpf`
 
 - Fix various 'perf test' cases for s390.
 
 - Build system cleanups, bump minimum shellcheck version to 0.7.2
 
 - Support building the capstone based annotation routines as a plugin.
 
 - Allow passing extra Clang flags via EXTRA_BPF_FLAGS.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCaZn25QAKCRCyPKLppCJ+
 J9MbAQCTKChBwDsqVh5iPr0UAc+mez9LOPJFa580SYH9nmd1jgD+Oqip7xCf514G
 ZtYPNh+Mz0se0Mcb++syLUEjxvbrQQY=
 =y2VY
 -----END PGP SIGNATURE-----

Merge tag 'perf-tools-for-v7.0-1-2026-02-21' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools

Pull perf tools updates from Arnaldo Carvalho de Melo:

 - Introduce 'perf sched stats' tool with record/report/diff workflows
   using schedstat counters

 - Add a faster libdw based addr2line implementation and allow selecting
   it or its alternatives via 'perf config addr2line.style='

 - Data-type profiling fixes and improvements including the ability to
   select fields using 'perf report''s -F/-fields, e.g.:

     'perf report --fields overhead,type'

 - Add 'perf test' regression tests for Data-type profiling with C and
   Rust workloads

 - Fix srcline printing with inlines in callchains, make sure this has
   coverage in 'perf test'

 - Fix printing of leaf IP in LBR callchains

 - Fix display of metrics without sufficient permission in 'perf stat'

 - Print all machines in 'perf kvm report -vvv', not just the host

 - Switch from SHA-1 to BLAKE2s for build ID generation, remove SHA-1
   code

 - Fix 'perf report's histogram entry collapsing with '-F' option

 - Use system's cacheline size instead of a hardcoded value in 'perf
   report'

 - Allow filtering conversion by time range in 'perf data'

 - Cover conversion to CTF using 'perf data' in 'perf test'

 - Address newer glibc const-correctness (-Werror=discarded-qualifiers)
   issues

 - Fixes and improvements for ARM's CoreSight support, simplify ARM SPE
   event config in 'perf mem', update docs for 'perf c2c' including the
   ARM events it can be used with

 - Build support for generating metrics from arch specific python
   script, add extra AMD, Intel, ARM64 metrics using it

 - Add AMD Zen 6 events and metrics

 - Add JSON file with OpenHW Risc-V CVA6 hardware counters

 - Add 'perf kvm' stats live testing

 - Add more 'perf stat' tests to 'perf test'

 - Fix segfault in `perf lock contention -b/--use-bpf`

 - Fix various 'perf test' cases for s390

 - Build system cleanups, bump minimum shellcheck version to 0.7.2

 - Support building the capstone based annotation routines as a plugin

 - Allow passing extra Clang flags via EXTRA_BPF_FLAGS

* tag 'perf-tools-for-v7.0-1-2026-02-21' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: (255 commits)
  perf test script: Add python script testing support
  perf test script: Add perl script testing support
  perf script: Allow the generated script to be a path
  perf test: perf data --to-ctf testing
  perf test: Test pipe mode with data conversion --to-json
  perf json: Pipe mode --to-ctf support
  perf json: Pipe mode --to-json support
  perf check: Add libbabeltrace to the listed features
  perf build: Allow passing extra Clang flags via EXTRA_BPF_FLAGS
  perf test data_type_profiling.sh: Skip just the Rust tests if code_with_type workload is missing
  tools build: Fix feature test for rust compiler
  perf libunwind: Fix calls to thread__e_machine()
  perf stat: Add no-affinity flag
  perf evlist: Reduce affinity use and move into iterator, fix no affinity
  perf evlist: Missing TPEBS close in evlist__close()
  perf evlist: Special map propagation for tool events that read on 1 CPU
  perf stat-shadow: In prepare_metric fix guard on reading NULL perf_stat_evsel
  Revert "perf tool_pmu: More accurately set the cpus for tool events"
  tools build: Emit dependencies file for test-rust.bin
  tools build: Make test-rust.bin be removed by the 'clean' target
  ...
This commit is contained in:
Linus Torvalds 2026-02-21 10:51:08 -08:00
commit c7decec2f2
324 changed files with 15622 additions and 4400 deletions

View file

@ -1,2 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#include <asm/unistd_64.h>
/*
* Copyright (C) 2012 ARM Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define __ARCH_WANT_RENAMEAT
#define __ARCH_WANT_NEW_STAT
#define __ARCH_WANT_SET_GET_RLIMIT
#define __ARCH_WANT_TIME32_SYSCALLS
#define __ARCH_WANT_MEMFD_SECRET
#include <asm-generic/unistd.h>

View file

@ -76,6 +76,14 @@ quiet_cmd_host_ld_multi = HOSTLD $@
cmd_host_ld_multi = $(if $(strip $(obj-y)),\
$(HOSTLD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(HOSTAR) rcs $@)
rust_common_cmd = \
$(RUSTC) $(rust_flags) \
--crate-type staticlib -L $(objtree)/rust/ \
--emit=dep-info=$(depfile),link
quiet_cmd_rustc_a_rs = $(RUSTC) $(quiet_modtag) $@
cmd_rustc_a_rs = $(rust_common_cmd) -o $@ -g $< $(cmd_objtool)
ifneq ($(filter $(obj),$(hostprogs)),)
host = host_
endif
@ -105,6 +113,12 @@ $(OUTPUT)%.s: %.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_s_c)
# it's recommended to build a static rust library, when a foreight (to rust)
# linker is used.
$(OUTPUT)%.a: %.rs FORCE
$(call rule_mkdir)
$(call if_changed_dep,rustc_a_rs)
# bison and flex files are generated in the OUTPUT directory
# so it needs a separate rule to depend on them properly
$(OUTPUT)%-bison.o: $(OUTPUT)%-bison.c FORCE

View file

@ -71,7 +71,7 @@ FEATURE_TESTS_BASIC := \
gettid \
glibc \
libbfd \
libbfd-buildid \
libbfd-threadsafe \
libelf \
libelf-getphdrnum \
libelf-gelf_getnote \
@ -149,7 +149,8 @@ FEATURE_DISPLAY ?= \
bpf \
libaio \
libzstd \
libopenssl
libopenssl \
rust
#
# Declare group members of a feature to display the logical OR of the detection

View file

@ -13,7 +13,7 @@ FILES= \
test-gtk2-infobar.bin \
test-hello.bin \
test-libbfd.bin \
test-libbfd-buildid.bin \
test-libbfd-threadsafe.bin \
test-disassembler-four-args.bin \
test-disassembler-init-styled.bin \
test-reallocarray.bin \
@ -73,6 +73,7 @@ FILES= \
test-clang-bpf-co-re.bin \
test-file-handle.bin \
test-libpfm4.bin \
test-rust.bin \
test-libopenssl.bin
FILES := $(addprefix $(OUTPUT),$(FILES))
@ -268,7 +269,7 @@ $(OUTPUT)test-libpython.bin:
$(OUTPUT)test-libbfd.bin:
$(BUILD_BFD)
$(OUTPUT)test-libbfd-buildid.bin:
$(OUTPUT)test-libbfd-threadsafe.bin:
$(BUILD_BFD) || $(BUILD_BFD) -liberty || $(BUILD_BFD) -liberty -lz
$(OUTPUT)test-disassembler-four-args.bin:
@ -388,6 +389,15 @@ $(OUTPUT)test-libopenssl.bin:
$(OUTPUT)test-bpftool-skeletons.bin:
$(SYSTEM_BPFTOOL) version | grep '^features:.*skeletons' \
> $(@:.bin=.make.output) 2>&1
# Testing Rust is special: we don't compile anything, it's enough to check the
# compiler presence. Compiling a test code for this purposes is problematic,
# because Rust will emit a dependency file without any external references,
# meaning that if rustc will be removed the build process will still think it's
# there.
$(OUTPUT)test-rust.bin:
$(RUSTC) --version > /dev/null 2>&1
###############################
clean:

View file

@ -1,8 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <bfd.h>
int main(void)
{
bfd *abfd = bfd_openr("Pedro", 0);
return abfd && (!abfd->build_id || abfd->build_id->size > 0x506564726f);
}

View file

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
#include <bfd.h>
static bool lock(void *unused)
{
return true;
}
static bool unlock(void *unused)
{
return true;
}
int main(void)
{
/* Check for presence of new thread safety API (version 2.42) */
return !bfd_thread_init(lock, unlock, NULL);
}

View file

@ -8,6 +8,7 @@
#define _LINUX_BITFIELD_H
#include <linux/build_bug.h>
#include <linux/kernel.h>
#include <asm/byteorder.h>
/*

View file

@ -169,6 +169,16 @@ static inline void list_move_tail(struct list_head *list,
list_add_tail(list, head);
}
/**
* list_is_first -- tests whether @list is the first entry in list @head
* @list: the entry to test
* @head: the head of the list
*/
static inline int list_is_first(const struct list_head *list, const struct list_head *head)
{
return list->prev == head;
}
/**
* list_is_last - tests whether @list is the last entry in list @head
* @list: the entry to test

View file

@ -211,6 +211,8 @@ SYNOPSIS
struct perf_record_header_feature;
struct perf_record_compressed;
struct perf_record_compressed2;
struct perf_record_schedstat_cpu;
struct perf_record_schedstat_domain;
--
DESCRIPTION

View file

@ -42,7 +42,6 @@ libdir_relative_SQ = $(subst ','\'',$(libdir_relative))
TEST_ARGS := $(if $(V),-v)
INCLUDES = \
-I$(OUTPUT)arch/$(SRCARCH)/include/generated/uapi \
-I$(srctree)/tools/lib/perf/include \
-I$(srctree)/tools/lib/ \
-I$(srctree)/tools/include \
@ -51,9 +50,9 @@ INCLUDES = \
-I$(srctree)/tools/include/uapi
# Append required CFLAGS
override CFLAGS := $(INCLUDES) $(CFLAGS)
override CFLAGS += -g -Werror -Wall
override CFLAGS += -fPIC
override CFLAGS += $(INCLUDES)
override CFLAGS += -fvisibility=hidden
override CFLAGS += $(EXTRA_WARNINGS)
override CFLAGS += $(EXTRA_CFLAGS)
@ -100,16 +99,7 @@ $(LIBAPI)-clean:
$(call QUIET_CLEAN, libapi)
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
uapi-asm := $(OUTPUT)arch/$(SRCARCH)/include/generated/uapi/asm
ifeq ($(SRCARCH),arm64)
syscall-y := $(uapi-asm)/unistd_64.h
endif
uapi-asm-generic:
$(if $(syscall-y),\
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-headers obj=$(uapi-asm) \
generic=include/uapi/asm-generic $(syscall-y),)
$(LIBPERF_IN): uapi-asm-generic FORCE
$(LIBPERF_IN): FORCE
$(Q)$(MAKE) $(build)=libperf
$(LIBPERF_A): $(LIBPERF_IN)
@ -130,7 +120,7 @@ all: fixdep
clean: $(LIBAPI)-clean
$(call QUIET_CLEAN, libperf) $(RM) $(LIBPERF_A) \
*.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBPERF_VERSION) .*.d .*.cmd tests/*.o LIBPERF-CFLAGS $(LIBPERF_PC) \
$(TESTS_STATIC) $(TESTS_SHARED) $(syscall-y)
$(TESTS_STATIC) $(TESTS_SHARED)
TESTS_IN = tests-in.o
@ -179,6 +169,7 @@ install_lib: libs
cp -fpR $(LIBPERF_ALL) $(DESTDIR)$(libdir_SQ)
HDRS := bpf_perf.h core.h cpumap.h threadmap.h evlist.h evsel.h event.h mmap.h
HDRS += schedstat-v15.h schedstat-v16.h schedstat-v17.h
INTERNAL_HDRS := cpumap.h evlist.h evsel.h lib.h mmap.h rc_check.h threadmap.h xyarray.h
INSTALL_HDRS_PFX := $(DESTDIR)$(prefix)/include/perf

View file

@ -101,6 +101,28 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
evsel->cpus = perf_cpu_map__get(evlist->user_requested_cpus);
}
/*
* Tool events may only read on the first CPU index to avoid double
* counting things like duration_time. Make the evsel->cpus contain just
* that single entry otherwise we may spend time changing affinity to
* CPUs that just have tool events, etc.
*/
if (evsel->reads_only_on_cpu_idx0 && perf_cpu_map__nr(evsel->cpus) > 0) {
struct perf_cpu_map *srcs[3] = {
evlist->all_cpus,
evlist->user_requested_cpus,
evsel->pmu_cpus,
};
for (size_t i = 0; i < ARRAY_SIZE(srcs); i++) {
if (!srcs[i])
continue;
perf_cpu_map__put(evsel->cpus);
evsel->cpus = perf_cpu_map__new_int(perf_cpu_map__cpu(srcs[i], 0).cpu);
break;
}
}
/* Sanity check assert before the evsel is potentially removed. */
assert(!evsel->requires_cpu || !perf_cpu_map__has_any_cpu(evsel->cpus));
@ -133,16 +155,22 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
static void perf_evlist__propagate_maps(struct perf_evlist *evlist)
{
struct perf_evsel *evsel, *n;
evlist->needs_map_propagation = true;
/* Clear the all_cpus set which will be merged into during propagation. */
perf_cpu_map__put(evlist->all_cpus);
evlist->all_cpus = NULL;
list_for_each_entry_safe(evsel, n, &evlist->entries, node)
__perf_evlist__propagate_maps(evlist, evsel);
/* 2 rounds so that reads_only_on_cpu_idx0 benefit from knowing the other CPU maps. */
for (int round = 0; round < 2; round++) {
struct perf_evsel *evsel, *n;
list_for_each_entry_safe(evsel, n, &evlist->entries, node) {
if ((!evsel->reads_only_on_cpu_idx0 && round == 0) ||
(evsel->reads_only_on_cpu_idx0 && round == 1))
__perf_evlist__propagate_maps(evlist, evsel);
}
}
}
void perf_evlist__add(struct perf_evlist *evlist,

View file

@ -128,6 +128,8 @@ struct perf_evsel {
bool requires_cpu;
/** Is the PMU for the event a core one? Effects the handling of own_cpus. */
bool is_pmu_core;
/** Does the evsel on read on the first CPU index such as tool time events? */
bool reads_only_on_cpu_idx0;
int idx;
};

View file

@ -496,6 +496,71 @@ struct perf_record_bpf_metadata {
struct perf_record_bpf_metadata_entry entries[];
};
struct perf_record_schedstat_cpu_v15 {
#define CPU_FIELD(_type, _name, _desc, _format, _is_pct, _pct_of, _ver) _type _name
#include "schedstat-v15.h"
#undef CPU_FIELD
};
struct perf_record_schedstat_cpu_v16 {
#define CPU_FIELD(_type, _name, _desc, _format, _is_pct, _pct_of, _ver) _type _name
#include "schedstat-v16.h"
#undef CPU_FIELD
};
struct perf_record_schedstat_cpu_v17 {
#define CPU_FIELD(_type, _name, _desc, _format, _is_pct, _pct_of, _ver) _type _name
#include "schedstat-v17.h"
#undef CPU_FIELD
};
struct perf_record_schedstat_cpu {
struct perf_event_header header;
__u64 timestamp;
__u32 cpu;
__u16 version;
/* Padding */
char __pad[2];
union {
struct perf_record_schedstat_cpu_v15 v15;
struct perf_record_schedstat_cpu_v16 v16;
struct perf_record_schedstat_cpu_v17 v17;
};
};
struct perf_record_schedstat_domain_v15 {
#define DOMAIN_FIELD(_type, _name, _desc, _format, _is_jiffies, _ver) _type _name
#include "schedstat-v15.h"
#undef DOMAIN_FIELD
};
struct perf_record_schedstat_domain_v16 {
#define DOMAIN_FIELD(_type, _name, _desc, _format, _is_jiffies, _ver) _type _name
#include "schedstat-v16.h"
#undef DOMAIN_FIELD
};
struct perf_record_schedstat_domain_v17 {
#define DOMAIN_FIELD(_type, _name, _desc, _format, _is_jiffies, _ver) _type _name
#include "schedstat-v17.h"
#undef DOMAIN_FIELD
};
#define DOMAIN_NAME_LEN 16
struct perf_record_schedstat_domain {
struct perf_event_header header;
__u64 timestamp;
__u32 cpu;
__u16 version;
__u16 domain;
union {
struct perf_record_schedstat_domain_v15 v15;
struct perf_record_schedstat_domain_v16 v16;
struct perf_record_schedstat_domain_v17 v17;
};
};
enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_USER_TYPE_START = 64,
PERF_RECORD_HEADER_ATTR = 64,
@ -519,6 +584,8 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_FINISHED_INIT = 82,
PERF_RECORD_COMPRESSED2 = 83,
PERF_RECORD_BPF_METADATA = 84,
PERF_RECORD_SCHEDSTAT_CPU = 85,
PERF_RECORD_SCHEDSTAT_DOMAIN = 86,
PERF_RECORD_HEADER_MAX
};
@ -562,6 +629,8 @@ union perf_event {
struct perf_record_compressed pack;
struct perf_record_compressed2 pack2;
struct perf_record_bpf_metadata bpf_metadata;
struct perf_record_schedstat_cpu schedstat_cpu;
struct perf_record_schedstat_domain schedstat_domain;
};
#endif /* __LIBPERF_EVENT_H */

View file

@ -0,0 +1,146 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifdef CPU_FIELD
CPU_FIELD(__u32, yld_count, "sched_yield() count",
"%11u", false, yld_count, v15);
CPU_FIELD(__u32, array_exp, "Legacy counter can be ignored",
"%11u", false, array_exp, v15);
CPU_FIELD(__u32, sched_count, "schedule() called",
"%11u", false, sched_count, v15);
CPU_FIELD(__u32, sched_goidle, "schedule() left the processor idle",
"%11u", true, sched_count, v15);
CPU_FIELD(__u32, ttwu_count, "try_to_wake_up() was called",
"%11u", false, ttwu_count, v15);
CPU_FIELD(__u32, ttwu_local, "try_to_wake_up() was called to wake up the local cpu",
"%11u", true, ttwu_count, v15);
CPU_FIELD(__u64, rq_cpu_time, "total runtime by tasks on this processor (in jiffies)",
"%11llu", false, rq_cpu_time, v15);
CPU_FIELD(__u64, run_delay, "total waittime by tasks on this processor (in jiffies)",
"%11llu", true, rq_cpu_time, v15);
CPU_FIELD(__u64, pcount, "total timeslices run on this cpu",
"%11llu", false, pcount, v15);
#endif
#ifdef DOMAIN_FIELD
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category idle> ");
#endif
DOMAIN_FIELD(__u32, idle_lb_count,
"load_balance() count on cpu idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, idle_lb_balanced,
"load_balance() found balanced on cpu idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, idle_lb_failed,
"load_balance() move task failed on cpu idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, idle_lb_imbalance,
"imbalance sum on cpu idle", "%11u", false, v15);
DOMAIN_FIELD(__u32, idle_lb_gained,
"pull_task() count on cpu idle", "%11u", false, v15);
DOMAIN_FIELD(__u32, idle_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu idle", "%11u", false, v15);
DOMAIN_FIELD(__u32, idle_lb_nobusyq,
"load_balance() failed to find busier queue on cpu idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, idle_lb_nobusyg,
"load_balance() failed to find busier group on cpu idle", "%11u", true, v15);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(idle_lb_success_count, "load_balance() success count on cpu idle", "%11u",
idle_lb_count, idle_lb_balanced, idle_lb_failed, v15);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(idle_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu idle)", "%11.2Lf",
idle_lb_count, idle_lb_balanced, idle_lb_failed, idle_lb_gained, v15);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category busy> ");
#endif
DOMAIN_FIELD(__u32, busy_lb_count,
"load_balance() count on cpu busy", "%11u", true, v15);
DOMAIN_FIELD(__u32, busy_lb_balanced,
"load_balance() found balanced on cpu busy", "%11u", true, v15);
DOMAIN_FIELD(__u32, busy_lb_failed,
"load_balance() move task failed on cpu busy", "%11u", true, v15);
DOMAIN_FIELD(__u32, busy_lb_imbalance,
"imbalance sum on cpu busy", "%11u", false, v15);
DOMAIN_FIELD(__u32, busy_lb_gained,
"pull_task() count on cpu busy", "%11u", false, v15);
DOMAIN_FIELD(__u32, busy_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu busy", "%11u", false, v15);
DOMAIN_FIELD(__u32, busy_lb_nobusyq,
"load_balance() failed to find busier queue on cpu busy", "%11u", true, v15);
DOMAIN_FIELD(__u32, busy_lb_nobusyg,
"load_balance() failed to find busier group on cpu busy", "%11u", true, v15);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(busy_lb_success_count, "load_balance() success count on cpu busy", "%11u",
busy_lb_count, busy_lb_balanced, busy_lb_failed, v15);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(busy_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu busy)", "%11.2Lf",
busy_lb_count, busy_lb_balanced, busy_lb_failed, busy_lb_gained, v15);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category newidle> ");
#endif
DOMAIN_FIELD(__u32, newidle_lb_count,
"load_balance() count on cpu newly idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, newidle_lb_balanced,
"load_balance() found balanced on cpu newly idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, newidle_lb_failed,
"load_balance() move task failed on cpu newly idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, newidle_lb_imbalance,
"imbalance sum on cpu newly idle", "%11u", false, v15);
DOMAIN_FIELD(__u32, newidle_lb_gained,
"pull_task() count on cpu newly idle", "%11u", false, v15);
DOMAIN_FIELD(__u32, newidle_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu newly idle", "%11u", false, v15);
DOMAIN_FIELD(__u32, newidle_lb_nobusyq,
"load_balance() failed to find busier queue on cpu newly idle", "%11u", true, v15);
DOMAIN_FIELD(__u32, newidle_lb_nobusyg,
"load_balance() failed to find busier group on cpu newly idle", "%11u", true, v15);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(newidle_lb_success_count,
"load_balance() success count on cpu newly idle", "%11u",
newidle_lb_count, newidle_lb_balanced, newidle_lb_failed, v15);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(newidle_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu newly idle)", "%11.2Lf",
newidle_lb_count, newidle_lb_balanced, newidle_lb_failed, newidle_lb_gained, v15);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category active_load_balance()> ");
#endif
DOMAIN_FIELD(__u32, alb_count,
"active_load_balance() count", "%11u", false, v15);
DOMAIN_FIELD(__u32, alb_failed,
"active_load_balance() move task failed", "%11u", false, v15);
DOMAIN_FIELD(__u32, alb_pushed,
"active_load_balance() successfully moved a task", "%11u", false, v15);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category sched_balance_exec()> ");
#endif
DOMAIN_FIELD(__u32, sbe_count,
"sbe_count is not used", "%11u", false, v15);
DOMAIN_FIELD(__u32, sbe_balanced,
"sbe_balanced is not used", "%11u", false, v15);
DOMAIN_FIELD(__u32, sbe_pushed,
"sbe_pushed is not used", "%11u", false, v15);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category sched_balance_fork()> ");
#endif
DOMAIN_FIELD(__u32, sbf_count,
"sbf_count is not used", "%11u", false, v15);
DOMAIN_FIELD(__u32, sbf_balanced,
"sbf_balanced is not used", "%11u", false, v15);
DOMAIN_FIELD(__u32, sbf_pushed,
"sbf_pushed is not used", "%11u", false, v15);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Wakeup Info> ");
#endif
DOMAIN_FIELD(__u32, ttwu_wake_remote,
"try_to_wake_up() awoke a task that last ran on a diff cpu", "%11u", false, v15);
DOMAIN_FIELD(__u32, ttwu_move_affine,
"try_to_wake_up() moved task because cache-cold on own cpu", "%11u", false, v15);
DOMAIN_FIELD(__u32, ttwu_move_balance,
"try_to_wake_up() started passive balancing", "%11u", false, v15);
#endif /* DOMAIN_FIELD */

View file

@ -0,0 +1,146 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifdef CPU_FIELD
CPU_FIELD(__u32, yld_count, "sched_yield() count",
"%11u", false, yld_count, v16);
CPU_FIELD(__u32, array_exp, "Legacy counter can be ignored",
"%11u", false, array_exp, v16);
CPU_FIELD(__u32, sched_count, "schedule() called",
"%11u", false, sched_count, v16);
CPU_FIELD(__u32, sched_goidle, "schedule() left the processor idle",
"%11u", true, sched_count, v16);
CPU_FIELD(__u32, ttwu_count, "try_to_wake_up() was called",
"%11u", false, ttwu_count, v16);
CPU_FIELD(__u32, ttwu_local, "try_to_wake_up() was called to wake up the local cpu",
"%11u", true, ttwu_count, v16);
CPU_FIELD(__u64, rq_cpu_time, "total runtime by tasks on this processor (in jiffies)",
"%11llu", false, rq_cpu_time, v16);
CPU_FIELD(__u64, run_delay, "total waittime by tasks on this processor (in jiffies)",
"%11llu", true, rq_cpu_time, v16);
CPU_FIELD(__u64, pcount, "total timeslices run on this cpu",
"%11llu", false, pcount, v16);
#endif /* CPU_FIELD */
#ifdef DOMAIN_FIELD
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category busy> ");
#endif
DOMAIN_FIELD(__u32, busy_lb_count,
"load_balance() count on cpu busy", "%11u", true, v16);
DOMAIN_FIELD(__u32, busy_lb_balanced,
"load_balance() found balanced on cpu busy", "%11u", true, v16);
DOMAIN_FIELD(__u32, busy_lb_failed,
"load_balance() move task failed on cpu busy", "%11u", true, v16);
DOMAIN_FIELD(__u32, busy_lb_imbalance,
"imbalance sum on cpu busy", "%11u", false, v16);
DOMAIN_FIELD(__u32, busy_lb_gained,
"pull_task() count on cpu busy", "%11u", false, v16);
DOMAIN_FIELD(__u32, busy_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu busy", "%11u", false, v16);
DOMAIN_FIELD(__u32, busy_lb_nobusyq,
"load_balance() failed to find busier queue on cpu busy", "%11u", true, v16);
DOMAIN_FIELD(__u32, busy_lb_nobusyg,
"load_balance() failed to find busier group on cpu busy", "%11u", true, v16);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(busy_lb_success_count, "load_balance() success count on cpu busy", "%11u",
busy_lb_count, busy_lb_balanced, busy_lb_failed, v16);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(busy_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu busy)", "%11.2Lf",
busy_lb_count, busy_lb_balanced, busy_lb_failed, busy_lb_gained, v16);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category idle> ");
#endif
DOMAIN_FIELD(__u32, idle_lb_count,
"load_balance() count on cpu idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, idle_lb_balanced,
"load_balance() found balanced on cpu idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, idle_lb_failed,
"load_balance() move task failed on cpu idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, idle_lb_imbalance,
"imbalance sum on cpu idle", "%11u", false, v16);
DOMAIN_FIELD(__u32, idle_lb_gained,
"pull_task() count on cpu idle", "%11u", false, v16);
DOMAIN_FIELD(__u32, idle_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu idle", "%11u", false, v16);
DOMAIN_FIELD(__u32, idle_lb_nobusyq,
"load_balance() failed to find busier queue on cpu idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, idle_lb_nobusyg,
"load_balance() failed to find busier group on cpu idle", "%11u", true, v16);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(idle_lb_success_count, "load_balance() success count on cpu idle", "%11u",
idle_lb_count, idle_lb_balanced, idle_lb_failed, v16);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(idle_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu idle)", "%11.2Lf",
idle_lb_count, idle_lb_balanced, idle_lb_failed, idle_lb_gained, v16);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category newidle> ");
#endif
DOMAIN_FIELD(__u32, newidle_lb_count,
"load_balance() count on cpu newly idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, newidle_lb_balanced,
"load_balance() found balanced on cpu newly idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, newidle_lb_failed,
"load_balance() move task failed on cpu newly idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, newidle_lb_imbalance,
"imbalance sum on cpu newly idle", "%11u", false, v16);
DOMAIN_FIELD(__u32, newidle_lb_gained,
"pull_task() count on cpu newly idle", "%11u", false, v16);
DOMAIN_FIELD(__u32, newidle_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu newly idle", "%11u", false, v16);
DOMAIN_FIELD(__u32, newidle_lb_nobusyq,
"load_balance() failed to find busier queue on cpu newly idle", "%11u", true, v16);
DOMAIN_FIELD(__u32, newidle_lb_nobusyg,
"load_balance() failed to find busier group on cpu newly idle", "%11u", true, v16);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(newidle_lb_success_count,
"load_balance() success count on cpu newly idle", "%11u",
newidle_lb_count, newidle_lb_balanced, newidle_lb_failed, v16);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(newidle_lb_avg_count,
"avg task pulled per successful lb attempt (cpu newly idle)", "%11.2Lf",
newidle_lb_count, newidle_lb_balanced, newidle_lb_failed, newidle_lb_gained, v16);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category active_load_balance()> ");
#endif
DOMAIN_FIELD(__u32, alb_count,
"active_load_balance() count", "%11u", false, v16);
DOMAIN_FIELD(__u32, alb_failed,
"active_load_balance() move task failed", "%11u", false, v16);
DOMAIN_FIELD(__u32, alb_pushed,
"active_load_balance() successfully moved a task", "%11u", false, v16);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category sched_balance_exec()> ");
#endif
DOMAIN_FIELD(__u32, sbe_count,
"sbe_count is not used", "%11u", false, v16);
DOMAIN_FIELD(__u32, sbe_balanced,
"sbe_balanced is not used", "%11u", false, v16);
DOMAIN_FIELD(__u32, sbe_pushed,
"sbe_pushed is not used", "%11u", false, v16);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category sched_balance_fork()> ");
#endif
DOMAIN_FIELD(__u32, sbf_count,
"sbf_count is not used", "%11u", false, v16);
DOMAIN_FIELD(__u32, sbf_balanced,
"sbf_balanced is not used", "%11u", false, v16);
DOMAIN_FIELD(__u32, sbf_pushed,
"sbf_pushed is not used", "%11u", false, v16);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Wakeup Info> ");
#endif
DOMAIN_FIELD(__u32, ttwu_wake_remote,
"try_to_wake_up() awoke a task that last ran on a diff cpu", "%11u", false, v16);
DOMAIN_FIELD(__u32, ttwu_move_affine,
"try_to_wake_up() moved task because cache-cold on own cpu", "%11u", false, v16);
DOMAIN_FIELD(__u32, ttwu_move_balance,
"try_to_wake_up() started passive balancing", "%11u", false, v16);
#endif /* DOMAIN_FIELD */

View file

@ -0,0 +1,164 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifdef CPU_FIELD
CPU_FIELD(__u32, yld_count, "sched_yield() count",
"%11u", false, yld_count, v17);
CPU_FIELD(__u32, array_exp, "Legacy counter can be ignored",
"%11u", false, array_exp, v17);
CPU_FIELD(__u32, sched_count, "schedule() called",
"%11u", false, sched_count, v17);
CPU_FIELD(__u32, sched_goidle, "schedule() left the processor idle",
"%11u", true, sched_count, v17);
CPU_FIELD(__u32, ttwu_count, "try_to_wake_up() was called",
"%11u", false, ttwu_count, v17);
CPU_FIELD(__u32, ttwu_local, "try_to_wake_up() was called to wake up the local cpu",
"%11u", true, ttwu_count, v17);
CPU_FIELD(__u64, rq_cpu_time, "total runtime by tasks on this processor (in jiffies)",
"%11llu", false, rq_cpu_time, v17);
CPU_FIELD(__u64, run_delay, "total waittime by tasks on this processor (in jiffies)",
"%11llu", true, rq_cpu_time, v17);
CPU_FIELD(__u64, pcount, "total timeslices run on this cpu",
"%11llu", false, pcount, v17);
#endif /* CPU_FIELD */
#ifdef DOMAIN_FIELD
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category busy> ");
#endif
DOMAIN_FIELD(__u32, busy_lb_count,
"load_balance() count on cpu busy", "%11u", true, v17);
DOMAIN_FIELD(__u32, busy_lb_balanced,
"load_balance() found balanced on cpu busy", "%11u", true, v17);
DOMAIN_FIELD(__u32, busy_lb_failed,
"load_balance() move task failed on cpu busy", "%11u", true, v17);
DOMAIN_FIELD(__u32, busy_lb_imbalance_load,
"imbalance in load on cpu busy", "%11u", false, v17);
DOMAIN_FIELD(__u32, busy_lb_imbalance_util,
"imbalance in utilization on cpu busy", "%11u", false, v17);
DOMAIN_FIELD(__u32, busy_lb_imbalance_task,
"imbalance in number of tasks on cpu busy", "%11u", false, v17);
DOMAIN_FIELD(__u32, busy_lb_imbalance_misfit,
"imbalance in misfit tasks on cpu busy", "%11u", false, v17);
DOMAIN_FIELD(__u32, busy_lb_gained,
"pull_task() count on cpu busy", "%11u", false, v17);
DOMAIN_FIELD(__u32, busy_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu busy", "%11u", false, v17);
DOMAIN_FIELD(__u32, busy_lb_nobusyq,
"load_balance() failed to find busier queue on cpu busy", "%11u", true, v17);
DOMAIN_FIELD(__u32, busy_lb_nobusyg,
"load_balance() failed to find busier group on cpu busy", "%11u", true, v17);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(busy_lb_success_count, "load_balance() success count on cpu busy", "%11u",
busy_lb_count, busy_lb_balanced, busy_lb_failed, v17);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(busy_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu busy)", "%11.2Lf",
busy_lb_count, busy_lb_balanced, busy_lb_failed, busy_lb_gained, v17);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category idle> ");
#endif
DOMAIN_FIELD(__u32, idle_lb_count,
"load_balance() count on cpu idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, idle_lb_balanced,
"load_balance() found balanced on cpu idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, idle_lb_failed,
"load_balance() move task failed on cpu idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, idle_lb_imbalance_load,
"imbalance in load on cpu idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, idle_lb_imbalance_util,
"imbalance in utilization on cpu idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, idle_lb_imbalance_task,
"imbalance in number of tasks on cpu idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, idle_lb_imbalance_misfit,
"imbalance in misfit tasks on cpu idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, idle_lb_gained,
"pull_task() count on cpu idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, idle_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, idle_lb_nobusyq,
"load_balance() failed to find busier queue on cpu idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, idle_lb_nobusyg,
"load_balance() failed to find busier group on cpu idle", "%11u", true, v17);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(idle_lb_success_count, "load_balance() success count on cpu idle", "%11u",
idle_lb_count, idle_lb_balanced, idle_lb_failed, v17);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(idle_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu idle)", "%11.2Lf",
idle_lb_count, idle_lb_balanced, idle_lb_failed, idle_lb_gained, v17);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category newidle> ");
#endif
DOMAIN_FIELD(__u32, newidle_lb_count,
"load_balance() count on cpu newly idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, newidle_lb_balanced,
"load_balance() found balanced on cpu newly idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, newidle_lb_failed,
"load_balance() move task failed on cpu newly idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, newidle_lb_imbalance_load,
"imbalance in load on cpu newly idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, newidle_lb_imbalance_util,
"imbalance in utilization on cpu newly idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, newidle_lb_imbalance_task,
"imbalance in number of tasks on cpu newly idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, newidle_lb_imbalance_misfit,
"imbalance in misfit tasks on cpu newly idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, newidle_lb_gained,
"pull_task() count on cpu newly idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, newidle_lb_hot_gained,
"pull_task() when target task was cache-hot on cpu newly idle", "%11u", false, v17);
DOMAIN_FIELD(__u32, newidle_lb_nobusyq,
"load_balance() failed to find busier queue on cpu newly idle", "%11u", true, v17);
DOMAIN_FIELD(__u32, newidle_lb_nobusyg,
"load_balance() failed to find busier group on cpu newly idle", "%11u", true, v17);
#ifdef DERIVED_CNT_FIELD
DERIVED_CNT_FIELD(newidle_lb_success_count,
"load_balance() success count on cpu newly idle", "%11u",
newidle_lb_count, newidle_lb_balanced, newidle_lb_failed, v17);
#endif
#ifdef DERIVED_AVG_FIELD
DERIVED_AVG_FIELD(newidle_lb_avg_pulled,
"avg task pulled per successful lb attempt (cpu newly idle)", "%11.2Lf",
newidle_lb_count, newidle_lb_balanced, newidle_lb_failed, newidle_lb_gained, v17);
#endif
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category active_load_balance()> ");
#endif
DOMAIN_FIELD(__u32, alb_count,
"active_load_balance() count", "%11u", false, v17);
DOMAIN_FIELD(__u32, alb_failed,
"active_load_balance() move task failed", "%11u", false, v17);
DOMAIN_FIELD(__u32, alb_pushed,
"active_load_balance() successfully moved a task", "%11u", false, v17);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category sched_balance_exec()> ");
#endif
DOMAIN_FIELD(__u32, sbe_count,
"sbe_count is not used", "%11u", false, v17);
DOMAIN_FIELD(__u32, sbe_balanced,
"sbe_balanced is not used", "%11u", false, v17);
DOMAIN_FIELD(__u32, sbe_pushed,
"sbe_pushed is not used", "%11u", false, v17);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Category sched_balance_fork()> ");
#endif
DOMAIN_FIELD(__u32, sbf_count,
"sbf_count is not used", "%11u", false, v17);
DOMAIN_FIELD(__u32, sbf_balanced,
"sbf_balanced is not used", "%11u", false, v17);
DOMAIN_FIELD(__u32, sbf_pushed,
"sbf_pushed is not used", "%11u", false, v17);
#ifdef DOMAIN_CATEGORY
DOMAIN_CATEGORY(" <Wakeup Info> ");
#endif
DOMAIN_FIELD(__u32, ttwu_wake_remote,
"try_to_wake_up() awoke a task that last ran on a diff cpu", "%11u", false, v17);
DOMAIN_FIELD(__u32, ttwu_move_affine,
"try_to_wake_up() moved task because cache-cold on own cpu", "%11u", false, v17);
DOMAIN_FIELD(__u32, ttwu_move_balance,
"try_to_wake_up() started passive balancing", "%11u", false, v17);
#endif /* DOMAIN_FIELD */

View file

@ -97,11 +97,13 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
ei++;
}
}
if (ci != cj) {
while (ci < cmds->cnt) {
cmds->names[cj++] = cmds->names[ci];
cmds->names[ci++] = NULL;
while (ci < cmds->cnt) {
if (ci != cj) {
cmds->names[cj] = cmds->names[ci];
cmds->names[ci] = NULL;
}
ci++;
cj++;
}
for (ci = cj; ci < cmds->cnt; ci++)
assert(cmds->names[ci] == NULL);

View file

@ -36,12 +36,18 @@ config.mak.autogen
util/intel-pt-decoder/inat-tables.c
arch/*/include/generated/
trace/beauty/generated/
pmu-events/arch/common/common/legacy-cache.json
pmu-events/pmu-events.c
pmu-events/jevents
pmu-events/metric_test.log
pmu-events/empty-pmu-events.log
pmu-events/test-empty-pmu-events.c
*.shellcheck_log
pmu-events/arch/**/extra-metrics.json
pmu-events/arch/**/extra-metricgroups.json
tests/shell/*.shellcheck_log
tests/shell/coresight/*.shellcheck_log
tests/shell/lib/*.shellcheck_log
feature/
libapi/
libbpf/

View file

@ -160,20 +160,43 @@ Following perf record options are configured by default:
-W,-d,--phys-data,--sample-cpu
Unless specified otherwise with '-e' option, following events are monitored by
default on Intel:
The following table lists the events monitored on different architectures.
Unless specified otherwise with the -e option, the tool will select the
default events.
cpu/mem-loads,ldlat=30/P
cpu/mem-stores/P
following on AMD:
ibs_op//
and following on PowerPC:
cpu/mem-loads/
cpu/mem-stores/
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
| Arch | Configuration | Options | Events |
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
| Intel | Default | -e ldlat-loads | cpu/mem-loads,ldlat=30/P |
| | | -e ldlat-stores | cpu/mem-stores/P |
| |---------------+-----------------+--------------------------------------------------------------------------------+
| | Load only | -e ldlat-loads | cpu/mem-loads,ldlat=30/P |
| |---------------+-----------------+--------------------------------------------------------------------------------+
| | Store only | -e ldlat-stores | cpu/mem-stores/P |
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
| Intel | Default | -e ldlat-loads | {cpu/mem-loads-aux/,cpu/mem-loads,ldlat=30/}:P |
| with | | -e ldlat-stores | cpu/mem-stores/P |
| AUX |--------------+------------------+--------------------------------------------------------------------------------+
| | Load only | -e ldlat-loads | {cpu/mem-loads-aux/,cpu/mem-loads,ldlat=30/}:P |
| |---------------+-----------------+--------------------------------------------------------------------------------+
| | Store only | -e ldlat-stores | cpu/mem-stores/P |
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
| AMD | Default | -e mem-ldst | ibs_op// (without latency support) |
| | | | ibs_op/ldlat=30/ (with latency support) |
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
| PowerPC| Default | -e ldlat-loads | cpu/mem-loads/ |
| | | -e ldlat-stores | cpu/mem-stores/ |
| |---------------+-----------------+--------------------------------------------------------------------------------+
| | Load only | -e ldlat-loads | cpu/mem-loads/ |
| |---------------+-----------------+--------------------------------------------------------------------------------+
| | Store only | -e ldlat-stores | cpu/mem-stores/ |
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
| Arm | Default | -e spe-ldst | arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=30/ |
| SPE |---------------+-----------------+--------------------------------------------------------------------------------+
| | Load only | -e spe-load | arm_spe_0/ts_enable=1,pa_enable=1,load_filter=1,min_latency=30/ |
| |---------------+-----------------+--------------------------------------------------------------------------------+
| | Store only | -e spe-store | arm_spe_0/ts_enable=1,pa_enable=1,store_filter=1/ |
+--------+---------------+-----------------+--------------------------------------------------------------------------------+
User can pass any 'perf record' option behind '--' mark, like (to enable
callchains and system wide monitoring):

View file

@ -40,6 +40,34 @@ OPTIONS for 'convert'
--force::
Don't complain, do it.
--time::
Only convert samples within given time window: <start>,<stop>. Times
have the format seconds.nanoseconds. If start is not given (i.e. time
string is ',x.y') then analysis starts at the beginning of the file. If
stop time is not given (i.e. time string is 'x.y,') then analysis goes
to end of file. Multiple ranges can be separated by spaces, which
requires the argument to be quoted e.g. --time "1234.567,1234.789 1235,"
Also support time percent with multiple time ranges. Time string is
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
For example:
Select the second 10% time slice:
perf data convert --to-json out.json --time 10%/2
Select from 0% to 10% time slice:
perf data convert --to-json out.json --time 0%-10%
Select the first and second 10% time slices:
perf data convert --to-json out.json --time 10%/1,10%/2
Select from 0% to 10% and 30% to 40% slices:
perf data convert --to-json out.json --time 0%-10%,30%-40%
-v::
--verbose::
Be more verbose (show counter open errors, etc).

View file

@ -109,6 +109,11 @@ include::itrace.txt[]
should be used, and also --buildid-all and --switch-events may be
useful.
--convert-callchain::
Parse DWARF callchains and convert them to usual callchains. This also
discards stack and register data from the samples. This will lose
inlined callchain entries.
:GMEXAMPLECMD: inject
:GMEXAMPLESUBCMD:
include::guestmount.txt[]

View file

@ -344,7 +344,8 @@ OPTIONS
-d::
--data::
Record the sample virtual addresses. Implies --sample-mem-info.
Record the sample virtual addresses. Implies --sample-mem-info and
--data-mmap.
--phys-data::
Record the sample physical addresses.
@ -454,7 +455,7 @@ following filters are defined:
- no_tx: only when the target is not in a hardware transaction
- abort_tx: only when the target is a hardware transaction abort
- cond: conditional branches
- call_stack: save call stack
- stack: save call stack
- no_flags: don't save branch flags e.g prediction, misprediction etc
- no_cycles: don't save branch cycles
- hw_index: save branch hardware index
@ -861,6 +862,11 @@ filtered through the mask provided by -C option.
Prepare BPF filter to be used by regular users. The action should be
either "pin" or "unpin". The filter can be used after it's pinned.
--data-mmap::
Enable recording MMAP events for non-executable mappings. Basically
perf only records executable mappings but data mmaping can be useful
when you analyze data access with sample addresses. So using -d option
would enable this unless you specify --no-data-mmap manually.
include::intel-hybrid.txt[]

View file

@ -8,7 +8,7 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
SYNOPSIS
--------
[verse]
'perf sched' {record|latency|map|replay|script|timehist}
'perf sched' {record|latency|map|replay|script|timehist|stats}
DESCRIPTION
-----------
@ -80,8 +80,267 @@ There are several variants of 'perf sched':
Times are in msec.usec.
'perf sched stats {record | report | diff} <command>' to capture, report the diff
in schedstat counters and show the difference between perf sched stats report
respectively. schedstat counters which are present in the linux kernel and are
exposed through the file ``/proc/schedstat``. These counters are enabled or disabled
via the sysctl governed by the file ``/proc/sys/kernel/sched_schedstats``. These
counters accounts for many scheduler events such as ``schedule()`` calls, load-balancing
events, ``try_to_wakeup()`` call among others. This is useful in understanding the
scheduler behavior for the workload.
Note: The tool will not give correct results if there is topological reordering or
online/offline of cpus in between capturing snapshots of `/proc/schedstat`.
Example usage:
perf sched stats record -- sleep 1
perf sched stats report
perf sched stats diff
A detailed description of the schedstats can be found in the Kernel Documentation:
https://www.kernel.org/doc/html/latest/scheduler/sched-stats.html
The result can be interpreted as follows:
The `perf sched stats report` starts with description of the columns present in
the report. These column names are given before cpu and domain stats to improve
the readability of the report.
----------------------------------------------------------------------------------------------------
DESC -> Description of the field
COUNT -> Value of the field
PCT_CHANGE -> Percent change with corresponding base value
AVG_JIFFIES -> Avg time in jiffies between two consecutive occurrence of event
----------------------------------------------------------------------------------------------------
Next is the total profiling time in terms of jiffies:
----------------------------------------------------------------------------------------------------
Time elapsed (in jiffies) : 2323
----------------------------------------------------------------------------------------------------
Next is CPU scheduling statistics. These are simple diffs of /proc/schedstat CPU lines
along with description. The report also prints % relative to base stat.
In the example below, schedule() left the CPU0 idle 36.58% of the time. 0.45% of total
try_to_wake_up() was to wakeup local CPU. And, the total waittime by tasks on CPU0 is
48.70% of the total runtime by tasks on the same CPU.
----------------------------------------------------------------------------------------------------
CPU 0
----------------------------------------------------------------------------------------------------
DESC COUNT PCT_CHANGE
----------------------------------------------------------------------------------------------------
yld_count : 0
array_exp : 0
sched_count : 402267
sched_goidle : 147161 ( 36.58% )
ttwu_count : 236309
ttwu_local : 1062 ( 0.45% )
rq_cpu_time : 7083791148
run_delay : 3449973971 ( 48.70% )
pcount : 255035
----------------------------------------------------------------------------------------------------
Next is load balancing statistics. For each of the sched domains
(eg: `SMT`, `MC`, `DIE`...), the scheduler computes statistics under
the following three categories:
1) Idle Load Balance: Load balancing performed on behalf of a long
idling CPU by some other CPU.
2) Busy Load Balance: Load balancing performed when the CPU was busy.
3) New Idle Balance : Load balancing performed when a CPU just became
idle.
Under each of these three categories, sched stats report provides
different load balancing statistics. Along with direct stats, the
report also contains derived metrics prefixed with *. Example:
----------------------------------------------------------------------------------------------------
CPU 0, DOMAIN SMT CPUS 0,64
----------------------------------------------------------------------------------------------------
DESC COUNT AVG_JIFFIES
----------------------------------------- <Category busy> ------------------------------------------
busy_lb_count : 136 $ 17.08 $
busy_lb_balanced : 131 $ 17.73 $
busy_lb_failed : 0 $ 0.00 $
busy_lb_imbalance_load : 58
busy_lb_imbalance_util : 0
busy_lb_imbalance_task : 0
busy_lb_imbalance_misfit : 0
busy_lb_gained : 7
busy_lb_hot_gained : 0
busy_lb_nobusyq : 2 $ 1161.50 $
busy_lb_nobusyg : 129 $ 18.01 $
*busy_lb_success_count : 5
*busy_lb_avg_pulled : 1.40
----------------------------------------- <Category idle> ------------------------------------------
idle_lb_count : 449 $ 5.17 $
idle_lb_balanced : 382 $ 6.08 $
idle_lb_failed : 3 $ 774.33 $
idle_lb_imbalance_load : 0
idle_lb_imbalance_util : 0
idle_lb_imbalance_task : 71
idle_lb_imbalance_misfit : 0
idle_lb_gained : 67
idle_lb_hot_gained : 0
idle_lb_nobusyq : 0 $ 0.00 $
idle_lb_nobusyg : 382 $ 6.08 $
*idle_lb_success_count : 64
*idle_lb_avg_pulled : 1.05
---------------------------------------- <Category newidle> ----------------------------------------
newidle_lb_count : 30471 $ 0.08 $
newidle_lb_balanced : 28490 $ 0.08 $
newidle_lb_failed : 633 $ 3.67 $
newidle_lb_imbalance_load : 0
newidle_lb_imbalance_util : 0
newidle_lb_imbalance_task : 2040
newidle_lb_imbalance_misfit : 0
newidle_lb_gained : 1348
newidle_lb_hot_gained : 0
newidle_lb_nobusyq : 6 $ 387.17 $
newidle_lb_nobusyg : 26634 $ 0.09 $
*newidle_lb_success_count : 1348
*newidle_lb_avg_pulled : 1.00
----------------------------------------------------------------------------------------------------
Consider following line:
newidle_lb_balanced : 28490 $ 0.08 $
While profiling was active, the load-balancer found 28490 times the load
needs to be balanced on a newly idle CPU 0. Following value encapsulated
inside $ is average jiffies between two events (2323 / 28490 = 0.08).
Next are active_load_balance() stats. alb did not trigger while the
profiling was active, hence it's all 0s.
--------------------------------- <Category active_load_balance()> ---------------------------------
alb_count : 0
alb_failed : 0
alb_pushed : 0
----------------------------------------------------------------------------------------------------
Next are sched_balance_exec() and sched_balance_fork() stats. They are
not used but we kept it in RFC just for legacy purpose. Unless opposed,
we plan to remove them in next revision.
Next are wakeup statistics. For every domain, the report also shows
task-wakeup statistics. Example:
------------------------------------------ <Wakeup Info> -------------------------------------------
ttwu_wake_remote : 1590
ttwu_move_affine : 84
ttwu_move_balance : 0
----------------------------------------------------------------------------------------------------
Same set of stats are reported for each CPU and each domain level.
How to interpret the diff
~~~~~~~~~~~~~~~~~~~~~~~~~
The `perf sched stats diff` will also start with explaining the columns
present in the diff. Then it will show the diff in time in terms of
jiffies. The order of the values depends on the order of input data
files. It will take `perf.data.old` and `perf.data` respectively as the
defaults for comparison. Example:
----------------------------------------------------------------------------------------------------
Time elapsed (in jiffies) : 2009, 2001
----------------------------------------------------------------------------------------------------
Below is the sample representing the difference in cpu and domain stats of
two runs. Here third column or the values enclosed in `|...|` shows the
percent change between the two. Second and fourth columns shows the
side-by-side representions of the corresponding fields from `perf sched
stats report`.
----------------------------------------------------------------------------------------------------
CPU <ALL CPUS SUMMARY>
----------------------------------------------------------------------------------------------------
DESC COUNT1 COUNT2 PCT_CHANG>
----------------------------------------------------------------------------------------------------
yld_count : 0, 0 | 0.00>
array_exp : 0, 0 | 0.00>
sched_count : 528533, 412573 | -21.94>
sched_goidle : 193426, 146082 | -24.48>
ttwu_count : 313134, 385975 | 23.26>
ttwu_local : 1126, 1282 | 13.85>
rq_cpu_time : 8257200244, 8301250047 | 0.53>
run_delay : 4728347053, 3997100703 | -15.47>
pcount : 335031, 266396 | -20.49>
----------------------------------------------------------------------------------------------------
Below is the sample of domain stats diff:
----------------------------------------------------------------------------------------------------
CPU <ALL CPUS SUMMARY>, DOMAIN SMT
----------------------------------------------------------------------------------------------------
DESC COUNT1 COUNT2 PCT_CHANG>
----------------------------------------- <Category busy> ------------------------------------------
busy_lb_count : 122, 80 | -34.43>
busy_lb_balanced : 115, 76 | -33.91>
busy_lb_failed : 1, 3 | 200.00>
busy_lb_imbalance_load : 35, 49 | 40.00>
busy_lb_imbalance_util : 0, 0 | 0.00>
busy_lb_imbalance_task : 0, 0 | 0.00>
busy_lb_imbalance_misfit : 0, 0 | 0.00>
busy_lb_gained : 7, 2 | -71.43>
busy_lb_hot_gained : 0, 0 | 0.00>
busy_lb_nobusyq : 0, 0 | 0.00>
busy_lb_nobusyg : 115, 76 | -33.91>
*busy_lb_success_count : 6, 1 | -83.33>
*busy_lb_avg_pulled : 1.17, 2.00 | 71.43>
----------------------------------------- <Category idle> ------------------------------------------
idle_lb_count : 568, 620 | 9.15>
idle_lb_balanced : 462, 449 | -2.81>
idle_lb_failed : 11, 21 | 90.91>
idle_lb_imbalance_load : 0, 0 | 0.00>
idle_lb_imbalance_util : 0, 0 | 0.00>
idle_lb_imbalance_task : 115, 189 | 64.35>
idle_lb_imbalance_misfit : 0, 0 | 0.00>
idle_lb_gained : 103, 169 | 64.08>
idle_lb_hot_gained : 0, 0 | 0.00>
idle_lb_nobusyq : 0, 0 | 0.00>
idle_lb_nobusyg : 462, 449 | -2.81>
*idle_lb_success_count : 95, 150 | 57.89>
*idle_lb_avg_pulled : 1.08, 1.13 | 3.92>
---------------------------------------- <Category newidle> ----------------------------------------
newidle_lb_count : 16961, 3155 | -81.40>
newidle_lb_balanced : 15646, 2556 | -83.66>
newidle_lb_failed : 397, 142 | -64.23>
newidle_lb_imbalance_load : 0, 0 | 0.00>
newidle_lb_imbalance_util : 0, 0 | 0.00>
newidle_lb_imbalance_task : 1376, 655 | -52.40>
newidle_lb_imbalance_misfit : 0, 0 | 0.00>
newidle_lb_gained : 917, 457 | -50.16>
newidle_lb_hot_gained : 0, 0 | 0.00>
newidle_lb_nobusyq : 3, 1 | -66.67>
newidle_lb_nobusyg : 14480, 2103 | -85.48>
*newidle_lb_success_count : 918, 457 | -50.22>
*newidle_lb_avg_pulled : 1.00, 1.00 | 0.11>
--------------------------------- <Category active_load_balance()> ---------------------------------
alb_count : 0, 1 | 0.00>
alb_failed : 0, 0 | 0.00>
alb_pushed : 0, 1 | 0.00>
--------------------------------- <Category sched_balance_exec()> ----------------------------------
sbe_count : 0, 0 | 0.00>
sbe_balanced : 0, 0 | 0.00>
sbe_pushed : 0, 0 | 0.00>
--------------------------------- <Category sched_balance_fork()> ----------------------------------
sbf_count : 0, 0 | 0.00>
sbf_balanced : 0, 0 | 0.00>
sbf_pushed : 0, 0 | 0.00>
------------------------------------------ <Wakeup Info> -------------------------------------------
ttwu_wake_remote : 2031, 2914 | 43.48>
ttwu_move_affine : 73, 124 | 69.86>
ttwu_move_balance : 0, 0 | 0.00>
----------------------------------------------------------------------------------------------------
OPTIONS
-------
Applicable to {record|latency|map|replay|script}
-i::
--input=<file>::
Input file name. (default: perf.data unless stdin is a fifo)

View file

@ -98,8 +98,10 @@ OPTIONS
-g::
--gen-script=::
Generate perf-script.[ext] starter script for given language,
using current perf.data.
Generate a starter script. If a language is given then the
script is named perf-script.[ext] according to the
language. If a file path is given then python is used for
files ending '.py' and perl used for files ending '.pl'.
--dlfilter=<file>::
Filter sample events using the given shared object file.

View file

@ -382,6 +382,11 @@ color the metric's computed value.
Don't print output, warnings or messages. This is useful with perf stat
record below to only write data to the perf.data file.
--no-affinity::
Don't change scheduler CPU affinities when iterating over
CPUs. Disables an optimization aimed at minimizing interprocessor
interrupts.
STAT RECORD
-----------
Stores stat data into perf data file.

View file

@ -447,6 +447,23 @@ struct {
} [nr_pmu];
};
HEADER_CPU_DOMAIN_INFO = 32,
List of cpu-domain relation info. The format of the data is as below.
struct domain_info {
int domain;
char dname[];
char cpumask[];
char cpulist[];
};
struct cpu_domain_info {
int cpu;
int nr_domains;
struct domain_info domains[];
};
other bits are reserved and should ignored for now
HEADER_FEAT_BITS = 256,

View file

@ -64,7 +64,6 @@ include $(srctree)/tools/scripts/Makefile.arch
$(call detected_var,SRCARCH)
CFLAGS += -I$(OUTPUT)arch/$(SRCARCH)/include/generated
CFLAGS += -I$(OUTPUT)libperf/arch/$(SRCARCH)/include/generated/uapi
# Additional ARCH settings for ppc
ifeq ($(SRCARCH),powerpc)
@ -118,14 +117,6 @@ ifeq ($(ARCH),mips)
endif
endif
# So far there's only x86 and arm libdw unwind support merged in perf.
# Disable it on all other architectures in case libdw unwind
# support is detected in system. Add supported architectures
# to the check.
ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky riscv loongarch))
NO_LIBDW_DWARF_UNWIND := 1
endif
ifneq ($(LIBUNWIND),1)
NO_LIBUNWIND := 1
endif
@ -379,8 +370,8 @@ ifneq ($(TCMALLOC),)
endif
ifeq ($(FEATURES_DUMP),)
# We will display at the end of this Makefile.config, using $(call feature_display_entries)
# As we may retry some feature detection here, see the disassembler-four-args case, for instance
# We will display at the end of this Makefile.config, using $(call feature_display_entries),
# as we may retry some feature detection here.
FEATURE_DISPLAY_DEFERRED := 1
include $(srctree)/tools/build/Makefile.feature
else
@ -456,7 +447,6 @@ endif
ifdef NO_LIBELF
NO_LIBDW := 1
NO_LIBUNWIND := 1
NO_LIBDW_DWARF_UNWIND := 1
NO_LIBBPF := 1
NO_JVMTI := 1
else
@ -504,10 +494,6 @@ ifeq ($(feature-libaio), 1)
endif
endif
ifdef NO_LIBDW
NO_LIBDW_DWARF_UNWIND := 1
endif
ifeq ($(feature-scandirat), 1)
# Ignore having scandirat with memory sanitizer that lacks an interceptor.
ifeq ($(filter s% -fsanitize=memory%,$(EXTRA_CFLAGS),),)
@ -757,7 +743,7 @@ dwarf-post-unwind-text := BUG
# setup DWARF post unwinder
ifdef NO_LIBUNWIND
ifdef NO_LIBDW_DWARF_UNWIND
ifdef NO_LIBDW
$(warning Disabling post unwind, no support found.)
dwarf-post-unwind := 0
else
@ -767,10 +753,6 @@ ifdef NO_LIBUNWIND
else
dwarf-post-unwind-text := libunwind
$(call detected,CONFIG_LIBUNWIND)
# Enable libunwind support by default.
ifndef NO_LIBDW_DWARF_UNWIND
NO_LIBDW_DWARF_UNWIND := 1
endif
endif
ifeq ($(dwarf-post-unwind),1)
@ -931,48 +913,32 @@ ifneq ($(NO_JEVENTS),1)
endif
ifdef BUILD_NONDISTRO
# call all detections now so we get correct status in VF output
$(call feature_check,libbfd)
$(call feature_check,disassembler-four-args)
$(call feature_check,disassembler-init-styled)
$(call feature_check,libbfd-threadsafe)
$(call feature_check,libbfd-liberty)
$(call feature_check,libbfd-liberty-z)
ifneq ($(feature-libbfd-threadsafe), 1)
$(error binutils 2.42 or later is required for non-distro builds)
endif
# we may be on a system that requires -liberty and (maybe) -lz
# to link against -lbfd; test each case individually here
ifeq ($(feature-libbfd), 1)
EXTLIBS += -lbfd -lopcodes
FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lbfd -lopcodes -ldl
FEATURE_CHECK_LDFLAGS-disassembler-init-styled = -lbfd -lopcodes -ldl
else
# we are on a system that requires -liberty and (maybe) -lz
# to link against -lbfd; test each case individually here
# call all detections now so we get correct
# status in VF output
$(call feature_check,libbfd-liberty)
$(call feature_check,libbfd-liberty-z)
ifeq ($(feature-libbfd-liberty), 1)
EXTLIBS += -lbfd -lopcodes -liberty
FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -ldl
FEATURE_CHECK_LDFLAGS-disassembler-init-styled += -liberty -ldl
else
ifeq ($(feature-libbfd-liberty-z), 1)
EXTLIBS += -lbfd -lopcodes -liberty -lz
FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -lz -ldl
FEATURE_CHECK_LDFLAGS-disassembler-init-styled += -liberty -lz -ldl
endif
endif
$(call feature_check,disassembler-four-args)
$(call feature_check,disassembler-init-styled)
else ifeq ($(feature-libbfd-liberty), 1)
EXTLIBS += -lbfd -lopcodes -liberty
else ifeq ($(feature-libbfd-liberty-z), 1)
EXTLIBS += -lbfd -lopcodes -liberty -lz
endif
CFLAGS += -DHAVE_LIBBFD_SUPPORT
CXXFLAGS += -DHAVE_LIBBFD_SUPPORT
$(call detected,CONFIG_LIBBFD)
$(call feature_check,libbfd-buildid)
ifeq ($(feature-libbfd-buildid), 1)
CFLAGS += -DHAVE_LIBBFD_BUILDID_SUPPORT
else
$(warning Old version of libbfd/binutils things like PE executable profiling will not be available)
endif
ifeq ($(feature-disassembler-four-args), 1)
CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
endif
@ -1067,10 +1033,6 @@ ifndef NO_LIBNUMA
endif
endif
ifdef HAVE_KVM_STAT_SUPPORT
CFLAGS += -DHAVE_KVM_STAT_SUPPORT
endif
ifeq (${IS_64_BIT}, 1)
ifndef NO_PERF_READ_VDSO32
$(call feature_check,compile-32)
@ -1112,8 +1074,12 @@ ifndef NO_CAPSTONE
$(call feature_check,libcapstone)
ifeq ($(feature-libcapstone), 1)
CFLAGS += -DHAVE_LIBCAPSTONE_SUPPORT $(LIBCAPSTONE_CFLAGS)
LDFLAGS += $(LICAPSTONE_LDFLAGS)
EXTLIBS += -lcapstone
ifdef LIBCAPSTONE_DLOPEN
CFLAGS += -DLIBCAPSTONE_DLOPEN
else
LDFLAGS += $(LIBCAPSTONE_LDFLAGS)
EXTLIBS += -lcapstone
endif
$(call detected,CONFIG_LIBCAPSTONE)
else
msg := $(warning No libcapstone found, disables disasm engine support for 'perf script', please install libcapstone-dev/capstone-devel);
@ -1187,6 +1153,18 @@ ifneq ($(NO_LIBTRACEEVENT),1)
endif
endif
ifndef NO_RUST
$(call feature_check,rust)
ifneq ($(feature-rust), 1)
$(warning Rust is not found. Test workloads with rust are disabled.)
NO_RUST := 1
else
NO_RUST := 0
CFLAGS += -DHAVE_RUST_SUPPORT
$(call detected,CONFIG_RUST_SUPPORT)
endif
endif
# Among the variables below, these:
# perfexecdir
# libbpf_include_dir
@ -1332,6 +1310,6 @@ endif
# re-generate FEATURE-DUMP as we may have called feature_check, found out
# extra libraries to add to LDFLAGS of some other test and then redo those
# tests, see the block about libbfd, disassembler-four-args, for instance.
# tests.
$(shell rm -f $(FEATURE_DUMP_FILENAME))
$(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))

View file

@ -35,6 +35,9 @@ include ../scripts/utilities.mak
#
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
#
# Define EXTRA_BPF_FLAGS="--sysroot=<path>" or other custom include paths for
# cross-compiling BPF skeletons
#
# Define EXCLUDE_EXTLIBS=-lmylib to exclude libmylib from the auto-generated
# EXTLIBS.
#
@ -86,8 +89,6 @@ include ../scripts/utilities.mak
#
# Define NO_LIBBPF if you do not want BPF support
#
# Define NO_LIBCAP if you do not want process capabilities considered by perf
#
# Define NO_SDT if you do not want to define SDT event in perf tools,
# note that it doesn't disable SDT scanning support.
#
@ -251,11 +252,12 @@ else
endif
# shellcheck is using in tools/perf/tests/Build with option -a/--check-sourced (
# introduced in v0.4.7) and -S/--severity (introduced in v0.6.0). So make the
# minimal shellcheck version as v0.6.0.
# introduced in v0.4.7) and -S/--severity (introduced in v0.6.0) as well as
# dynamic source inclusions (properly handled since v0.7.2).
# So make the minimal shellcheck version as v0.7.2.
ifneq ($(SHELLCHECK),)
ifeq ($(shell expr $(shell $(SHELLCHECK) --version | grep version: | \
sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \< 060), 1)
sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \< 072), 1)
SHELLCHECK :=
else
SHELLCHECK := $(SHELLCHECK) -s bash -a -S warning
@ -272,7 +274,7 @@ ifeq ($(PYLINT),1)
PYLINT := $(shell which pylint 2> /dev/null)
endif
export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK
export srctree OUTPUT RM CC CXX RUSTC LD AR CFLAGS CXXFLAGS V BISON FLEX AWK
export HOSTCC HOSTLD HOSTAR HOSTCFLAGS SHELLCHECK MYPY PYLINT
include $(srctree)/tools/build/Makefile.include
@ -807,11 +809,6 @@ $(GTK_IN): FORCE prepare
$(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS)
$(QUIET_LINK)$(CC) -o $@ -shared $(LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
$(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
$(SCRIPTS) : % : %.sh
$(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
@ -849,7 +846,7 @@ endif
__build-dir = $(subst $(OUTPUT),,$(dir $@))
build-dir = $(or $(__build-dir),.)
prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \
prepare: $(OUTPUT)PERF-VERSION-FILE archheaders \
arm64-sysreg-defs \
$(syscall_array) \
$(fs_at_flags_array) \
@ -1053,7 +1050,7 @@ cscope:
# However, the environment gets quite big, and some programs have problems
# with that.
check: $(OUTPUT)common-cmds.h
check: prepare
if sparse; \
then \
for i in *.c */*.c; \
@ -1250,7 +1247,7 @@ endif
$(SKEL_TMP_OUT)/%.bpf.o: $(OUTPUT)PERF-VERSION-FILE util/bpf_skel/perf_version.h | $(SKEL_TMP_OUT)
$(SKEL_TMP_OUT)/%.bpf.o: util/bpf_skel/%.bpf.c $(LIBBPF) $(SKEL_OUT)/vmlinux.h
$(QUIET_CLANG)$(CLANG) -g -O2 -fno-stack-protector --target=bpf \
$(CLANG_OPTIONS) $(BPF_INCLUDE) $(TOOLS_UAPI_INCLUDE) \
$(CLANG_OPTIONS) $(EXTRA_BPF_FLAGS) $(BPF_INCLUDE) $(TOOLS_UAPI_INCLUDE) \
-include $(OUTPUT)PERF-VERSION-FILE -include util/bpf_skel/perf_version.h \
-c $(filter util/bpf_skel/%.bpf.c,$^) -o $@
@ -1277,6 +1274,8 @@ ifeq ($(OUTPUT),)
pmu-events/metric_test.log \
pmu-events/test-empty-pmu-events.c \
pmu-events/empty-pmu-events.log
$(Q)find pmu-events/arch -name 'extra-metrics.json' -delete -o \
-name 'extra-metricgroups.json' -delete
else # When an OUTPUT directory is present, clean up the copied pmu-events/arch directory.
$(call QUIET_CLEAN, pmu-events) $(RM) -r $(OUTPUT)pmu-events/arch \
$(OUTPUT)pmu-events/pmu-events.c \
@ -1296,7 +1295,7 @@ clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 \
perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo \
$(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE \
TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE \
$(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
$(OUTPUT)util/intel-pt-decoder/inat-tables.c \
$(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \

View file

@ -1,11 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler.h>
static int arc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
arch->initialized = true;
arch->objdump.comment_char = ';';
arch->e_machine = EM_ARC;
arch->e_flags = 0;
return 0;
}

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/arm/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);

View file

@ -1,6 +1,3 @@
perf-util-y += perf_regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-y += pmu.o auxtrace.o cs-etm.o

View file

@ -68,6 +68,20 @@ static const char * const metadata_ete_ro[] = {
enum cs_etm_version { CS_NOT_PRESENT, CS_ETMV3, CS_ETMV4, CS_ETE };
/* ETMv4 CONFIGR register bits */
#define TRCCONFIGR_BB BIT(3)
#define TRCCONFIGR_CCI BIT(4)
#define TRCCONFIGR_CID BIT(6)
#define TRCCONFIGR_VMID BIT(7)
#define TRCCONFIGR_TS BIT(11)
#define TRCCONFIGR_RS BIT(12)
#define TRCCONFIGR_VMIDOPT BIT(15)
/* ETMv3 ETMCR register bits */
#define ETMCR_CYC_ACC BIT(12)
#define ETMCR_TIMESTAMP_EN BIT(28)
#define ETMCR_RETURN_STACK BIT(29)
static bool cs_etm_is_ete(struct perf_pmu *cs_etm_pmu, struct perf_cpu cpu);
static int cs_etm_get_ro(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path, __u64 *val);
static bool cs_etm_pmu_path_exists(struct perf_pmu *pmu, struct perf_cpu cpu, const char *path);
@ -89,13 +103,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
struct perf_cpu cpu)
{
int err;
__u64 val;
u64 contextid = evsel->core.attr.config &
(perf_pmu__format_bits(cs_etm_pmu, "contextid") |
perf_pmu__format_bits(cs_etm_pmu, "contextid1") |
perf_pmu__format_bits(cs_etm_pmu, "contextid2"));
u64 ctxt, ctxt1, ctxt2;
__u64 trcidr2;
if (!contextid)
evsel__get_config_val(evsel, "contextid", &ctxt);
evsel__get_config_val(evsel, "contextid1", &ctxt1);
evsel__get_config_val(evsel, "contextid2", &ctxt2);
if (!ctxt && !ctxt1 && !ctxt2)
return 0;
/* Not supported in etmv3 */
@ -106,12 +121,11 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
}
/* Get a handle on TRCIDR2 */
err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &val);
err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR2], &trcidr2);
if (err)
return err;
if (contextid &
perf_pmu__format_bits(cs_etm_pmu, "contextid1")) {
if (ctxt1) {
/*
* TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
* tracing is supported:
@ -119,15 +133,14 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
* 0b00100 Maximum of 32-bit Context ID size.
* All other values are reserved.
*/
if (BMVAL(val, 5, 9) != 0x4) {
if (BMVAL(trcidr2, 5, 9) != 0x4) {
pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
return -EINVAL;
}
}
if (contextid &
perf_pmu__format_bits(cs_etm_pmu, "contextid2")) {
if (ctxt2) {
/*
* TRCIDR2.VMIDOPT[30:29] != 0 and
* TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
@ -135,7 +148,7 @@ static int cs_etm_validate_context_id(struct perf_pmu *cs_etm_pmu, struct evsel
* virtual context id is < 32bit.
* Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
*/
if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
if (!BMVAL(trcidr2, 29, 30) || BMVAL(trcidr2, 10, 14) < 4) {
pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
return -EINVAL;
@ -149,10 +162,11 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
struct perf_cpu cpu)
{
int err;
__u64 val;
u64 val;
__u64 trcidr0;
if (!(evsel->core.attr.config &
perf_pmu__format_bits(cs_etm_pmu, "timestamp")))
evsel__get_config_val(evsel, "timestamp", &val);
if (!val)
return 0;
if (cs_etm_get_version(cs_etm_pmu, cpu) == CS_ETMV3) {
@ -162,7 +176,7 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
}
/* Get a handle on TRCIRD0 */
err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &val);
err = cs_etm_get_ro(cs_etm_pmu, cpu, metadata_etmv4_ro[CS_ETMV4_TRCIDR0], &trcidr0);
if (err)
return err;
@ -173,10 +187,9 @@ static int cs_etm_validate_timestamp(struct perf_pmu *cs_etm_pmu, struct evsel *
* 0b00110 Implementation supports a maximum timestamp of 48bits.
* 0b01000 Implementation supports a maximum timestamp of 64bits.
*/
val &= GENMASK(28, 24);
if (!val) {
trcidr0 &= GENMASK(28, 24);
if (!trcidr0)
return -EINVAL;
}
return 0;
}
@ -259,16 +272,19 @@ static int cs_etm_parse_snapshot_options(struct auxtrace_record *itr,
return 0;
}
/*
* If the sink name format "@sink_name" is used, lookup the sink by name to convert to
* "sinkid=sink_hash" format. If the user has already manually provided a hash then
* "sinkid" isn't overwritten. If neither are provided then the driver will pick the best
* sink.
*/
static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
struct evsel *evsel)
{
char msg[BUFSIZ], path[PATH_MAX], *sink;
struct evsel_config_term *term;
int ret = -EINVAL;
u32 hash;
if (evsel->core.attr.config2 & GENMASK(31, 0))
return 0;
int ret;
list_for_each_entry(term, &evsel->config_terms, list) {
if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)
@ -291,17 +307,26 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
return ret;
}
evsel->core.attr.config2 |= hash;
evsel__set_config_if_unset(evsel, "sinkid", hash);
return 0;
}
/*
* No sink was provided on the command line - allow the CoreSight
* system to look for a default
*/
return 0;
}
static struct evsel *cs_etm_get_evsel(struct evlist *evlist,
struct perf_pmu *cs_etm_pmu)
{
struct evsel *evsel;
evlist__for_each_entry(evlist, evsel) {
if (evsel->core.attr.type == cs_etm_pmu->type)
return evsel;
}
return NULL;
}
static int cs_etm_recording_options(struct auxtrace_record *itr,
struct evlist *evlist,
struct record_opts *opts)
@ -441,10 +466,8 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
* when a context switch happened.
*/
if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {
evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
"timestamp", 1);
evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
"contextid", 1);
evsel__set_config_if_unset(cs_etm_evsel, "timestamp", 1);
evsel__set_config_if_unset(cs_etm_evsel, "contextid", 1);
}
/*
@ -453,8 +476,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
* timestamp tracing.
*/
if (opts->sample_time_set)
evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
"timestamp", 1);
evsel__set_config_if_unset(cs_etm_evsel, "timestamp", 1);
/* Add dummy event to keep tracking */
err = parse_event(evlist, "dummy:u");
@ -474,64 +496,64 @@ out:
return err;
}
static u64 cs_etm_get_config(struct auxtrace_record *itr)
static u64 cs_etm_synth_etmcr(struct auxtrace_record *itr)
{
u64 config = 0;
struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr);
container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
struct evlist *evlist = ptr->evlist;
struct evsel *evsel;
struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
u64 etmcr = 0;
u64 val;
evlist__for_each_entry(evlist, evsel) {
if (evsel->core.attr.type == cs_etm_pmu->type) {
/*
* Variable perf_event_attr::config is assigned to
* ETMv3/PTM. The bit fields have been made to match
* the ETMv3.5 ETRMCR register specification. See the
* PMU_FORMAT_ATTR() declarations in
* drivers/hwtracing/coresight/coresight-perf.c for
* details.
*/
config = evsel->core.attr.config;
break;
}
}
return config;
}
#ifndef BIT
#define BIT(N) (1UL << (N))
#endif
static u64 cs_etmv4_get_config(struct auxtrace_record *itr)
{
u64 config = 0;
u64 config_opts = 0;
if (!evsel)
return 0;
/*
* The perf event variable config bits represent both
* the command line options and register programming
* bits in ETMv3/PTM. For ETMv4 we must remap options
* to real bits
* Synthesize what the kernel programmed into ETMCR based on
* what options the event was opened with. This doesn't have to be
* complete or 100% accurate, not all bits used by OpenCSD anyway.
*/
config_opts = cs_etm_get_config(itr);
if (config_opts & BIT(ETM_OPT_CYCACC))
config |= BIT(ETM4_CFG_BIT_CYCACC);
if (config_opts & BIT(ETM_OPT_CTXTID))
config |= BIT(ETM4_CFG_BIT_CTXTID);
if (config_opts & BIT(ETM_OPT_TS))
config |= BIT(ETM4_CFG_BIT_TS);
if (config_opts & BIT(ETM_OPT_RETSTK))
config |= BIT(ETM4_CFG_BIT_RETSTK);
if (config_opts & BIT(ETM_OPT_CTXTID2))
config |= BIT(ETM4_CFG_BIT_VMID) |
BIT(ETM4_CFG_BIT_VMID_OPT);
if (config_opts & BIT(ETM_OPT_BRANCH_BROADCAST))
config |= BIT(ETM4_CFG_BIT_BB);
if (!evsel__get_config_val(evsel, "cycacc", &val) && val)
etmcr |= ETMCR_CYC_ACC;
if (!evsel__get_config_val(evsel, "timestamp", &val) && val)
etmcr |= ETMCR_TIMESTAMP_EN;
if (!evsel__get_config_val(evsel, "retstack", &val) && val)
etmcr |= ETMCR_RETURN_STACK;
return config;
return etmcr;
}
static u64 cs_etmv4_synth_trcconfigr(struct auxtrace_record *itr)
{
u64 trcconfigr = 0;
struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, cs_etm_pmu);
u64 val;
if (!evsel)
return 0;
/*
* Synthesize what the kernel programmed into TRCCONFIGR based on
* what options the event was opened with. This doesn't have to be
* complete or 100% accurate, not all bits used by OpenCSD anyway.
*/
if (!evsel__get_config_val(evsel, "cycacc", &val) && val)
trcconfigr |= TRCCONFIGR_CCI;
if (!evsel__get_config_val(evsel, "contextid1", &val) && val)
trcconfigr |= TRCCONFIGR_CID;
if (!evsel__get_config_val(evsel, "timestamp", &val) && val)
trcconfigr |= TRCCONFIGR_TS;
if (!evsel__get_config_val(evsel, "retstack", &val) && val)
trcconfigr |= TRCCONFIGR_RS;
if (!evsel__get_config_val(evsel, "contextid2", &val) && val)
trcconfigr |= TRCCONFIGR_VMID | TRCCONFIGR_VMIDOPT;
if (!evsel__get_config_val(evsel, "branch_broadcast", &val) && val)
trcconfigr |= TRCCONFIGR_BB;
return trcconfigr;
}
static size_t
@ -653,7 +675,7 @@ static void cs_etm_save_etmv4_header(__u64 data[], struct auxtrace_record *itr,
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
/* Get trace configuration register */
data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_get_config(itr);
data[CS_ETMV4_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
/* traceID set to legacy version, in case new perf running on older system */
data[CS_ETMV4_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
@ -685,7 +707,7 @@ static void cs_etm_save_ete_header(__u64 data[], struct auxtrace_record *itr, st
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
/* Get trace configuration register */
data[CS_ETE_TRCCONFIGR] = cs_etmv4_get_config(itr);
data[CS_ETE_TRCCONFIGR] = cs_etmv4_synth_trcconfigr(itr);
/* traceID set to legacy version, in case new perf running on older system */
data[CS_ETE_TRCTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
@ -741,7 +763,7 @@ static void cs_etm_get_metadata(struct perf_cpu cpu, u32 *offset,
case CS_ETMV3:
magic = __perf_cs_etmv3_magic;
/* Get configuration register */
info->priv[*offset + CS_ETM_ETMCR] = cs_etm_get_config(itr);
info->priv[*offset + CS_ETM_ETMCR] = cs_etm_synth_etmcr(itr);
/* traceID set to legacy value in case new perf running on old system */
info->priv[*offset + CS_ETM_ETMTRACEIDR] = cs_etm_get_legacy_trace_id(cpu);
/* Get read-only information from sysFS */
@ -832,12 +854,11 @@ static int cs_etm_snapshot_start(struct auxtrace_record *itr)
{
struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr);
struct evsel *evsel;
struct evsel *evsel = cs_etm_get_evsel(ptr->evlist, ptr->cs_etm_pmu);
if (evsel)
return evsel__disable(evsel);
evlist__for_each_entry(ptr->evlist, evsel) {
if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
return evsel__disable(evsel);
}
return -EINVAL;
}

View file

@ -1,22 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "perf_regs.h"
#include "../../../util/perf_regs.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,39 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include "perf_regs.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "../../../util/sample.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[PERF_REG_ARM_MAX];
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_ARM_##r); \
val; \
})
dwarf_regs[0] = REG(R0);
dwarf_regs[1] = REG(R1);
dwarf_regs[2] = REG(R2);
dwarf_regs[3] = REG(R3);
dwarf_regs[4] = REG(R4);
dwarf_regs[5] = REG(R5);
dwarf_regs[6] = REG(R6);
dwarf_regs[7] = REG(R7);
dwarf_regs[8] = REG(R8);
dwarf_regs[9] = REG(R9);
dwarf_regs[10] = REG(R10);
dwarf_regs[11] = REG(FP);
dwarf_regs[12] = REG(IP);
dwarf_regs[13] = REG(SP);
dwarf_regs[14] = REG(LR);
dwarf_regs[15] = REG(PC);
return dwfl_thread_state_registers(thread, 0, PERF_REG_ARM_MAX,
dwarf_regs);
}

View file

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
PERF_HAVE_JITDUMP := 1
HAVE_KVM_STAT_SUPPORT := 1

View file

@ -5,7 +5,7 @@
#include <stdlib.h>
#include <linux/types.h>
#define perf_event_arm_regs perf_event_arm64_regs
#include <asm/perf_regs.h>
#include "../../../../arch/arm64/include/uapi/asm/perf_regs.h"
#undef perf_event_arm_regs
void perf_regs_load(u64 *regs);

View file

@ -1,5 +1,3 @@
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-y += ../../arm/util/auxtrace.o
perf-util-y += ../../arm/util/cs-etm.o
@ -9,6 +7,5 @@ perf-util-y += header.o
perf-util-y += hisi-ptt.o
perf-util-y += machine.o
perf-util-y += mem-events.o
perf-util-y += perf_regs.o
perf-util-y += pmu.o
perf-util-y += tsc.o

View file

@ -256,7 +256,7 @@ static __u64 arm_spe_pmu__sample_period(const struct perf_pmu *arm_spe_pmu)
static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
{
u64 bit;
u64 pa_enable_bit;
evsel->core.attr.freq = 0;
evsel->core.attr.sample_period = arm_spe_pmu__sample_period(evsel->pmu);
@ -274,7 +274,7 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
*/
if (!perf_cpu_map__is_any_cpu_or_is_empty(cpus)) {
evsel__set_sample_bit(evsel, CPU);
evsel__set_config_if_unset(evsel->pmu, evsel, "ts_enable", 1);
evsel__set_config_if_unset(evsel, "ts_enable", 1);
}
/*
@ -288,9 +288,10 @@ static void arm_spe_setup_evsel(struct evsel *evsel, struct perf_cpu_map *cpus)
* inform that the resulting output's SPE samples contain physical addresses
* where applicable.
*/
bit = perf_pmu__format_bits(evsel->pmu, "pa_enable");
if (evsel->core.attr.config & bit)
evsel__set_sample_bit(evsel, PHYS_ADDR);
if (!evsel__get_config_val(evsel, "pa_enable", &pa_enable_bit))
if (pa_enable_bit)
evsel__set_sample_bit(evsel, PHYS_ADDR);
}
static int arm_spe_setup_aux_buffer(struct record_opts *opts)
@ -397,6 +398,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
struct perf_cpu_map *cpus = evlist->core.user_requested_cpus;
bool discard = false;
int err;
u64 discard_bit;
sper->evlist = evlist;
@ -425,9 +427,8 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
evlist__for_each_entry_safe(evlist, tmp, evsel) {
if (evsel__is_aux_event(evsel)) {
arm_spe_setup_evsel(evsel, cpus);
if (evsel->core.attr.config &
perf_pmu__format_bits(evsel->pmu, "discard"))
discard = true;
if (!evsel__get_config_val(evsel, "discard", &discard_bit))
discard = !!discard_bit;
}
}

View file

@ -1,4 +1,3 @@
#include <linux/kernel.h>
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <stdio.h>

View file

@ -1,18 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "debug.h"
#include "symbol.h"
#include "callchain.h"
#include "callchain.h" // prototype of arch__add_leaf_frame_record_opts
#include "perf_regs.h"
#include "record.h"
#include "util/perf_regs.h"
#define SMPL_REG_MASK(b) (1ULL << (b))
void arch__add_leaf_frame_record_opts(struct record_opts *opts)
{
const struct sample_reg *sample_reg_masks = arch__sample_reg_masks();
opts->sample_user_regs |= sample_reg_masks[PERF_REG_ARM64_LR].mask;
opts->sample_user_regs |= SMPL_REG_MASK(PERF_REG_ARM64_LR);
}

View file

@ -6,7 +6,7 @@
#define E(t, n, s, l, a) { .tag = t, .name = n, .event_name = s, .ldlat = l, .aux_event = a }
struct perf_mem_event perf_mem_events_arm[PERF_MEM_EVENTS__MAX] = {
E("spe-load", "%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=0,min_latency=%u/", NULL, true, 0),
E("spe-store", "%s/ts_enable=1,pa_enable=1,load_filter=0,store_filter=1/", NULL, false, 0),
E("spe-load", "%s/ts_enable=1,pa_enable=1,load_filter=1,min_latency=%u/", NULL, true, 0),
E("spe-store", "%s/ts_enable=1,pa_enable=1,store_filter=1/", NULL, false, 0),
E("spe-ldst", "%s/ts_enable=1,pa_enable=1,load_filter=1,store_filter=1,min_latency=%u/", NULL, true, 0),
};

View file

@ -1,182 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <regex.h>
#include <string.h>
#include <sys/auxv.h>
#include <linux/kernel.h>
#include <linux/zalloc.h>
#include "perf_regs.h"
#include "../../../perf-sys.h"
#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/perf_regs.h"
#ifndef HWCAP_SVE
#define HWCAP_SVE (1 << 22)
#endif
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG(x0, PERF_REG_ARM64_X0),
SMPL_REG(x1, PERF_REG_ARM64_X1),
SMPL_REG(x2, PERF_REG_ARM64_X2),
SMPL_REG(x3, PERF_REG_ARM64_X3),
SMPL_REG(x4, PERF_REG_ARM64_X4),
SMPL_REG(x5, PERF_REG_ARM64_X5),
SMPL_REG(x6, PERF_REG_ARM64_X6),
SMPL_REG(x7, PERF_REG_ARM64_X7),
SMPL_REG(x8, PERF_REG_ARM64_X8),
SMPL_REG(x9, PERF_REG_ARM64_X9),
SMPL_REG(x10, PERF_REG_ARM64_X10),
SMPL_REG(x11, PERF_REG_ARM64_X11),
SMPL_REG(x12, PERF_REG_ARM64_X12),
SMPL_REG(x13, PERF_REG_ARM64_X13),
SMPL_REG(x14, PERF_REG_ARM64_X14),
SMPL_REG(x15, PERF_REG_ARM64_X15),
SMPL_REG(x16, PERF_REG_ARM64_X16),
SMPL_REG(x17, PERF_REG_ARM64_X17),
SMPL_REG(x18, PERF_REG_ARM64_X18),
SMPL_REG(x19, PERF_REG_ARM64_X19),
SMPL_REG(x20, PERF_REG_ARM64_X20),
SMPL_REG(x21, PERF_REG_ARM64_X21),
SMPL_REG(x22, PERF_REG_ARM64_X22),
SMPL_REG(x23, PERF_REG_ARM64_X23),
SMPL_REG(x24, PERF_REG_ARM64_X24),
SMPL_REG(x25, PERF_REG_ARM64_X25),
SMPL_REG(x26, PERF_REG_ARM64_X26),
SMPL_REG(x27, PERF_REG_ARM64_X27),
SMPL_REG(x28, PERF_REG_ARM64_X28),
SMPL_REG(x29, PERF_REG_ARM64_X29),
SMPL_REG(lr, PERF_REG_ARM64_LR),
SMPL_REG(sp, PERF_REG_ARM64_SP),
SMPL_REG(pc, PERF_REG_ARM64_PC),
SMPL_REG(vg, PERF_REG_ARM64_VG),
SMPL_REG_END
};
/* %xNUM */
#define SDT_OP_REGEX1 "^(x[1-2]?[0-9]|3[0-1])$"
/* [sp], [sp, NUM] */
#define SDT_OP_REGEX2 "^\\[sp(, )?([0-9]+)?\\]$"
static regex_t sdt_op_regex1, sdt_op_regex2;
static int sdt_init_op_regex(void)
{
static int initialized;
int ret = 0;
if (initialized)
return 0;
ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
if (ret)
goto error;
ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
if (ret)
goto free_regex1;
initialized = 1;
return 0;
free_regex1:
regfree(&sdt_op_regex1);
error:
pr_debug4("Regex compilation error.\n");
return ret;
}
/*
* SDT marker arguments on Arm64 uses %xREG or [sp, NUM], currently
* support these two formats.
*/
int arch_sdt_arg_parse_op(char *old_op, char **new_op)
{
int ret, new_len;
regmatch_t rm[5];
ret = sdt_init_op_regex();
if (ret < 0)
return ret;
if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
/* Extract xNUM */
new_len = 2; /* % NULL */
new_len += (int)(rm[1].rm_eo - rm[1].rm_so);
*new_op = zalloc(new_len);
if (!*new_op)
return -ENOMEM;
scnprintf(*new_op, new_len, "%%%.*s",
(int)(rm[1].rm_eo - rm[1].rm_so), old_op + rm[1].rm_so);
} else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
/* [sp], [sp, NUM] or [sp,NUM] */
new_len = 7; /* + ( % s p ) NULL */
/* If the argument is [sp], need to fill offset '0' */
if (rm[2].rm_so == -1)
new_len += 1;
else
new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
*new_op = zalloc(new_len);
if (!*new_op)
return -ENOMEM;
if (rm[2].rm_so == -1)
scnprintf(*new_op, new_len, "+0(%%sp)");
else
scnprintf(*new_op, new_len, "+%.*s(%%sp)",
(int)(rm[2].rm_eo - rm[2].rm_so),
old_op + rm[2].rm_so);
} else {
pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
return SDT_ARG_SKIP;
}
return SDT_ARG_VALID;
}
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_USER,
.disabled = 1,
.exclude_kernel = 1,
.sample_period = 1,
.sample_regs_user = PERF_REGS_MASK
};
int fd;
if (getauxval(AT_HWCAP) & HWCAP_SVE)
attr.sample_regs_user |= SMPL_REG_MASK(PERF_REG_ARM64_VG);
/*
* Check if the pmu supports perf extended regs, before
* returning the register mask to sample.
*/
if (attr.sample_regs_user != PERF_REGS_MASK) {
event_attr_init(&attr);
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd != -1) {
close(fd);
return attr.sample_regs_user;
}
}
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,61 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include "perf_regs.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "../../../util/sample.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[PERF_REG_ARM64_MAX], dwarf_pc;
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_ARM64_##r); \
val; \
})
dwarf_regs[0] = REG(X0);
dwarf_regs[1] = REG(X1);
dwarf_regs[2] = REG(X2);
dwarf_regs[3] = REG(X3);
dwarf_regs[4] = REG(X4);
dwarf_regs[5] = REG(X5);
dwarf_regs[6] = REG(X6);
dwarf_regs[7] = REG(X7);
dwarf_regs[8] = REG(X8);
dwarf_regs[9] = REG(X9);
dwarf_regs[10] = REG(X10);
dwarf_regs[11] = REG(X11);
dwarf_regs[12] = REG(X12);
dwarf_regs[13] = REG(X13);
dwarf_regs[14] = REG(X14);
dwarf_regs[15] = REG(X15);
dwarf_regs[16] = REG(X16);
dwarf_regs[17] = REG(X17);
dwarf_regs[18] = REG(X18);
dwarf_regs[19] = REG(X19);
dwarf_regs[20] = REG(X20);
dwarf_regs[21] = REG(X21);
dwarf_regs[22] = REG(X22);
dwarf_regs[23] = REG(X23);
dwarf_regs[24] = REG(X24);
dwarf_regs[25] = REG(X25);
dwarf_regs[26] = REG(X26);
dwarf_regs[27] = REG(X27);
dwarf_regs[28] = REG(X28);
dwarf_regs[29] = REG(X29);
dwarf_regs[30] = REG(LR);
dwarf_regs[31] = REG(SP);
if (!dwfl_thread_state_registers(thread, 0, PERF_REG_ARM64_MAX,
dwarf_regs))
return false;
dwarf_pc = REG(PC);
dwfl_thread_state_register_pc(thread, dwarf_pc);
return true;
}

View file

@ -1 +0,0 @@
perf-util-y += util/

View file

@ -6,7 +6,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/csky/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MASK ((1ULL << PERF_REG_CSKY_MAX) - 1)
#define PERF_REGS_MAX PERF_REG_CSKY_MAX

View file

@ -1,3 +0,0 @@
perf-util-y += perf_regs.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View file

@ -1,22 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "perf_regs.h"
#include "../../util/perf_regs.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,78 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
#include <elfutils/libdwfl.h>
#include "perf_regs.h"
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/event.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[PERF_REG_CSKY_MAX];
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_CSKY_##r); \
val; \
})
#if defined(__CSKYABIV2__)
dwarf_regs[0] = REG(A0);
dwarf_regs[1] = REG(A1);
dwarf_regs[2] = REG(A2);
dwarf_regs[3] = REG(A3);
dwarf_regs[4] = REG(REGS0);
dwarf_regs[5] = REG(REGS1);
dwarf_regs[6] = REG(REGS2);
dwarf_regs[7] = REG(REGS3);
dwarf_regs[8] = REG(REGS4);
dwarf_regs[9] = REG(REGS5);
dwarf_regs[10] = REG(REGS6);
dwarf_regs[11] = REG(REGS7);
dwarf_regs[12] = REG(REGS8);
dwarf_regs[13] = REG(REGS9);
dwarf_regs[14] = REG(SP);
dwarf_regs[15] = REG(LR);
dwarf_regs[16] = REG(EXREGS0);
dwarf_regs[17] = REG(EXREGS1);
dwarf_regs[18] = REG(EXREGS2);
dwarf_regs[19] = REG(EXREGS3);
dwarf_regs[20] = REG(EXREGS4);
dwarf_regs[21] = REG(EXREGS5);
dwarf_regs[22] = REG(EXREGS6);
dwarf_regs[23] = REG(EXREGS7);
dwarf_regs[24] = REG(EXREGS8);
dwarf_regs[25] = REG(EXREGS9);
dwarf_regs[26] = REG(EXREGS10);
dwarf_regs[27] = REG(EXREGS11);
dwarf_regs[28] = REG(EXREGS12);
dwarf_regs[29] = REG(EXREGS13);
dwarf_regs[30] = REG(EXREGS14);
dwarf_regs[31] = REG(TLS);
dwarf_regs[32] = REG(PC);
#else
dwarf_regs[0] = REG(SP);
dwarf_regs[1] = REG(REGS9);
dwarf_regs[2] = REG(A0);
dwarf_regs[3] = REG(A1);
dwarf_regs[4] = REG(A2);
dwarf_regs[5] = REG(A3);
dwarf_regs[6] = REG(REGS0);
dwarf_regs[7] = REG(REGS1);
dwarf_regs[8] = REG(REGS2);
dwarf_regs[9] = REG(REGS3);
dwarf_regs[10] = REG(REGS4);
dwarf_regs[11] = REG(REGS5);
dwarf_regs[12] = REG(REGS6);
dwarf_regs[13] = REG(REGS7);
dwarf_regs[14] = REG(REGS8);
dwarf_regs[15] = REG(LR);
#endif
dwfl_thread_state_register_pc(thread, REG(PC));
return dwfl_thread_state_registers(thread, 0, PERF_REG_CSKY_MAX,
dwarf_regs);
}

View file

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
PERF_HAVE_JITDUMP := 1
HAVE_KVM_STAT_SUPPORT := 1

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/loongarch/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MAX PERF_REG_LOONGARCH_MAX

View file

@ -1,6 +1,4 @@
perf-util-y += header.o
perf-util-y += perf_regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o

View file

@ -1,22 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "perf_regs.h"
#include "../../../util/perf_regs.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,57 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2020-2023 Loongson Technology Corporation Limited */
#include <elfutils/libdwfl.h>
#include "perf_regs.h"
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/sample.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[PERF_REG_LOONGARCH_MAX];
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_LOONGARCH_##r); \
val; \
})
dwarf_regs[0] = 0;
dwarf_regs[1] = REG(R1);
dwarf_regs[2] = REG(R2);
dwarf_regs[3] = REG(R3);
dwarf_regs[4] = REG(R4);
dwarf_regs[5] = REG(R5);
dwarf_regs[6] = REG(R6);
dwarf_regs[7] = REG(R7);
dwarf_regs[8] = REG(R8);
dwarf_regs[9] = REG(R9);
dwarf_regs[10] = REG(R10);
dwarf_regs[11] = REG(R11);
dwarf_regs[12] = REG(R12);
dwarf_regs[13] = REG(R13);
dwarf_regs[14] = REG(R14);
dwarf_regs[15] = REG(R15);
dwarf_regs[16] = REG(R16);
dwarf_regs[17] = REG(R17);
dwarf_regs[18] = REG(R18);
dwarf_regs[19] = REG(R19);
dwarf_regs[20] = REG(R20);
dwarf_regs[21] = REG(R21);
dwarf_regs[22] = REG(R22);
dwarf_regs[23] = REG(R23);
dwarf_regs[24] = REG(R24);
dwarf_regs[25] = REG(R25);
dwarf_regs[26] = REG(R26);
dwarf_regs[27] = REG(R27);
dwarf_regs[28] = REG(R28);
dwarf_regs[29] = REG(R29);
dwarf_regs[30] = REG(R30);
dwarf_regs[31] = REG(R31);
dwfl_thread_state_register_pc(thread, REG(PC));
return dwfl_thread_state_registers(thread, 0, PERF_REG_LOONGARCH_MAX, dwarf_regs);
}

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/mips/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MAX PERF_REG_MIPS_MAX

View file

@ -1,2 +1 @@
perf-util-y += perf_regs.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o

View file

@ -1,22 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "perf_regs.h"
#include "../../util/perf_regs.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_JITDUMP := 1

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/powerpc/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);

View file

@ -1,6 +1,4 @@
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-y += perf_regs.o
perf-util-y += mem-events.o
perf-util-y += pmu.o
perf-util-y += sym-handling.o
@ -9,5 +7,4 @@ perf-util-y += evsel.o
perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-y += auxtrace.o

View file

@ -1,240 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <string.h>
#include <regex.h>
#include <linux/zalloc.h>
#include "perf_regs.h"
#include "../../../util/perf_regs.h"
#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/header.h"
#include "../../../perf-sys.h"
#include "utils_header.h"
#include <linux/kernel.h>
#define PVR_POWER9 0x004E
#define PVR_POWER10 0x0080
#define PVR_POWER11 0x0082
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG(r0, PERF_REG_POWERPC_R0),
SMPL_REG(r1, PERF_REG_POWERPC_R1),
SMPL_REG(r2, PERF_REG_POWERPC_R2),
SMPL_REG(r3, PERF_REG_POWERPC_R3),
SMPL_REG(r4, PERF_REG_POWERPC_R4),
SMPL_REG(r5, PERF_REG_POWERPC_R5),
SMPL_REG(r6, PERF_REG_POWERPC_R6),
SMPL_REG(r7, PERF_REG_POWERPC_R7),
SMPL_REG(r8, PERF_REG_POWERPC_R8),
SMPL_REG(r9, PERF_REG_POWERPC_R9),
SMPL_REG(r10, PERF_REG_POWERPC_R10),
SMPL_REG(r11, PERF_REG_POWERPC_R11),
SMPL_REG(r12, PERF_REG_POWERPC_R12),
SMPL_REG(r13, PERF_REG_POWERPC_R13),
SMPL_REG(r14, PERF_REG_POWERPC_R14),
SMPL_REG(r15, PERF_REG_POWERPC_R15),
SMPL_REG(r16, PERF_REG_POWERPC_R16),
SMPL_REG(r17, PERF_REG_POWERPC_R17),
SMPL_REG(r18, PERF_REG_POWERPC_R18),
SMPL_REG(r19, PERF_REG_POWERPC_R19),
SMPL_REG(r20, PERF_REG_POWERPC_R20),
SMPL_REG(r21, PERF_REG_POWERPC_R21),
SMPL_REG(r22, PERF_REG_POWERPC_R22),
SMPL_REG(r23, PERF_REG_POWERPC_R23),
SMPL_REG(r24, PERF_REG_POWERPC_R24),
SMPL_REG(r25, PERF_REG_POWERPC_R25),
SMPL_REG(r26, PERF_REG_POWERPC_R26),
SMPL_REG(r27, PERF_REG_POWERPC_R27),
SMPL_REG(r28, PERF_REG_POWERPC_R28),
SMPL_REG(r29, PERF_REG_POWERPC_R29),
SMPL_REG(r30, PERF_REG_POWERPC_R30),
SMPL_REG(r31, PERF_REG_POWERPC_R31),
SMPL_REG(nip, PERF_REG_POWERPC_NIP),
SMPL_REG(msr, PERF_REG_POWERPC_MSR),
SMPL_REG(orig_r3, PERF_REG_POWERPC_ORIG_R3),
SMPL_REG(ctr, PERF_REG_POWERPC_CTR),
SMPL_REG(link, PERF_REG_POWERPC_LINK),
SMPL_REG(xer, PERF_REG_POWERPC_XER),
SMPL_REG(ccr, PERF_REG_POWERPC_CCR),
SMPL_REG(softe, PERF_REG_POWERPC_SOFTE),
SMPL_REG(trap, PERF_REG_POWERPC_TRAP),
SMPL_REG(dar, PERF_REG_POWERPC_DAR),
SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR),
SMPL_REG(sier, PERF_REG_POWERPC_SIER),
SMPL_REG(mmcra, PERF_REG_POWERPC_MMCRA),
SMPL_REG(mmcr0, PERF_REG_POWERPC_MMCR0),
SMPL_REG(mmcr1, PERF_REG_POWERPC_MMCR1),
SMPL_REG(mmcr2, PERF_REG_POWERPC_MMCR2),
SMPL_REG(mmcr3, PERF_REG_POWERPC_MMCR3),
SMPL_REG(sier2, PERF_REG_POWERPC_SIER2),
SMPL_REG(sier3, PERF_REG_POWERPC_SIER3),
SMPL_REG(pmc1, PERF_REG_POWERPC_PMC1),
SMPL_REG(pmc2, PERF_REG_POWERPC_PMC2),
SMPL_REG(pmc3, PERF_REG_POWERPC_PMC3),
SMPL_REG(pmc4, PERF_REG_POWERPC_PMC4),
SMPL_REG(pmc5, PERF_REG_POWERPC_PMC5),
SMPL_REG(pmc6, PERF_REG_POWERPC_PMC6),
SMPL_REG(sdar, PERF_REG_POWERPC_SDAR),
SMPL_REG(siar, PERF_REG_POWERPC_SIAR),
SMPL_REG_END
};
/* REG or %rREG */
#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$"
/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
static regex_t sdt_op_regex1, sdt_op_regex2;
static int sdt_init_op_regex(void)
{
static int initialized;
int ret = 0;
if (initialized)
return 0;
ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
if (ret)
goto error;
ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
if (ret)
goto free_regex1;
initialized = 1;
return 0;
free_regex1:
regfree(&sdt_op_regex1);
error:
pr_debug4("Regex compilation error.\n");
return ret;
}
/*
* Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
* Possible variants of OP are:
* Format Example
* -------------------------
* NUM(REG) 48(18)
* -NUM(REG) -48(18)
* NUM(%rREG) 48(%r18)
* -NUM(%rREG) -48(%r18)
* REG 18
* %rREG %r18
* iNUM i0
* i-NUM i-1
*
* SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
* and REG form with -mno-regnames. Here REG is general purpose register,
* which is in 0 to 31 range.
*/
int arch_sdt_arg_parse_op(char *old_op, char **new_op)
{
int ret, new_len;
regmatch_t rm[5];
char prefix;
/* Constant argument. Uprobe does not support it */
if (old_op[0] == 'i') {
pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
return SDT_ARG_SKIP;
}
ret = sdt_init_op_regex();
if (ret < 0)
return ret;
if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
/* REG or %rREG --> %gprREG */
new_len = 5; /* % g p r NULL */
new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
*new_op = zalloc(new_len);
if (!*new_op)
return -ENOMEM;
scnprintf(*new_op, new_len, "%%gpr%.*s",
(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
} else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
/*
* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
* +/-NUM(%gprREG)
*/
prefix = (rm[1].rm_so == -1) ? '+' : '-';
new_len = 8; /* +/- ( % g p r ) NULL */
new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
*new_op = zalloc(new_len);
if (!*new_op)
return -ENOMEM;
scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
(int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
} else {
pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
return SDT_ARG_SKIP;
}
return SDT_ARG_VALID;
}
uint64_t arch__intr_reg_mask(void)
{
struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_INTR,
.precise_ip = 1,
.disabled = 1,
.exclude_kernel = 1,
};
int fd;
u32 version;
u64 extended_mask = 0, mask = PERF_REGS_MASK;
/*
* Get the PVR value to set the extended
* mask specific to platform.
*/
version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF);
if (version == PVR_POWER9)
extended_mask = PERF_REG_PMU_MASK_300;
else if ((version == PVR_POWER10) || (version == PVR_POWER11))
extended_mask = PERF_REG_PMU_MASK_31;
else
return mask;
attr.sample_regs_intr = extended_mask;
attr.sample_period = 1;
event_attr_init(&attr);
/*
* check if the pmu supports perf extended regs, before
* returning the register mask to sample.
*/
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd != -1) {
close(fd);
mask |= extended_mask;
}
return mask;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -30,14 +30,6 @@
* The libdwfl code in this file is based on code from elfutils
* (libdwfl/argp-std.c, libdwfl/tests/addrcfi.c, etc).
*/
static char *debuginfo_path;
static const Dwfl_Callbacks offline_callbacks = {
.debuginfo_path = &debuginfo_path,
.find_debuginfo = dwfl_standard_find_debuginfo,
.section_address = dwfl_offline_section_address,
};
/*
* Use the DWARF expression for the Call-frame-address and determine
@ -149,44 +141,22 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
* yet used)
* -1 in case of errors
*/
static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc)
static int check_return_addr(struct dso *dso, Dwarf_Addr mapped_pc)
{
int rc = -1;
Dwfl *dwfl;
Dwfl_Module *mod;
Dwarf_Frame *frame;
int ra_regno;
Dwarf_Addr start = pc;
Dwarf_Addr end = pc;
Dwarf_Addr start = mapped_pc;
Dwarf_Addr end = mapped_pc;
bool signalp;
const char *exec_file = dso__long_name(dso);
dwfl = RC_CHK_ACCESS(dso)->dwfl;
dwfl = dso__libdw_dwfl(dso);
if (!dwfl)
return -1;
if (!dwfl) {
dwfl = dwfl_begin(&offline_callbacks);
if (!dwfl) {
pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
return -1;
}
mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1,
map_start, false);
if (!mod) {
pr_debug("dwfl_report_elf() failed %s\n",
dwarf_errmsg(-1));
/*
* We normally cache the DWARF debug info and never
* call dwfl_end(). But to prevent fd leak, free in
* case of error.
*/
dwfl_end(dwfl);
goto out;
}
RC_CHK_ACCESS(dso)->dwfl = dwfl;
}
mod = dwfl_addrmodule(dwfl, pc);
mod = dwfl_addrmodule(dwfl, mapped_pc);
if (!mod) {
pr_debug("dwfl_addrmodule() failed, %s\n", dwarf_errmsg(-1));
goto out;
@ -196,9 +166,9 @@ static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc)
* To work with split debug info files (eg: glibc), check both
* .eh_frame and .debug_frame sections of the ELF header.
*/
frame = get_eh_frame(mod, pc);
frame = get_eh_frame(mod, mapped_pc);
if (!frame) {
frame = get_dwarf_frame(mod, pc);
frame = get_dwarf_frame(mod, mapped_pc);
if (!frame)
goto out;
}
@ -264,7 +234,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
return skip_slot;
}
rc = check_return_addr(dso, map__start(al.map), ip);
rc = check_return_addr(dso, map__map_ip(al.map, ip));
pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n",
dso__long_name(dso), al.sym->name, ip, rc);

View file

@ -1,76 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include <linux/kernel.h>
#include "perf_regs.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "../../../util/sample.h"
/* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */
static const int special_regs[3][2] = {
{ 65, PERF_REG_POWERPC_LINK },
{ 101, PERF_REG_POWERPC_XER },
{ 109, PERF_REG_POWERPC_CTR },
};
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[32], dwarf_nip;
size_t i;
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_POWERPC_##r); \
val; \
})
dwarf_regs[0] = REG(R0);
dwarf_regs[1] = REG(R1);
dwarf_regs[2] = REG(R2);
dwarf_regs[3] = REG(R3);
dwarf_regs[4] = REG(R4);
dwarf_regs[5] = REG(R5);
dwarf_regs[6] = REG(R6);
dwarf_regs[7] = REG(R7);
dwarf_regs[8] = REG(R8);
dwarf_regs[9] = REG(R9);
dwarf_regs[10] = REG(R10);
dwarf_regs[11] = REG(R11);
dwarf_regs[12] = REG(R12);
dwarf_regs[13] = REG(R13);
dwarf_regs[14] = REG(R14);
dwarf_regs[15] = REG(R15);
dwarf_regs[16] = REG(R16);
dwarf_regs[17] = REG(R17);
dwarf_regs[18] = REG(R18);
dwarf_regs[19] = REG(R19);
dwarf_regs[20] = REG(R20);
dwarf_regs[21] = REG(R21);
dwarf_regs[22] = REG(R22);
dwarf_regs[23] = REG(R23);
dwarf_regs[24] = REG(R24);
dwarf_regs[25] = REG(R25);
dwarf_regs[26] = REG(R26);
dwarf_regs[27] = REG(R27);
dwarf_regs[28] = REG(R28);
dwarf_regs[29] = REG(R29);
dwarf_regs[30] = REG(R30);
dwarf_regs[31] = REG(R31);
if (!dwfl_thread_state_registers(thread, 0, 32, dwarf_regs))
return false;
dwarf_nip = REG(NIP);
dwfl_thread_state_register_pc(thread, dwarf_nip);
for (i = 0; i < ARRAY_SIZE(special_regs); i++) {
Dwarf_Word val = 0;
perf_reg_value(&val, user_regs, special_regs[i][1]);
if (!dwfl_thread_state_registers(thread,
special_regs[i][0], 1,
&val))
return false;
}
return true;
}

View file

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
PERF_HAVE_JITDUMP := 1
HAVE_KVM_STAT_SUPPORT := 1

View file

@ -6,14 +6,19 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/riscv/include/uapi/asm/perf_regs.h"
#define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
#define PERF_REGS_MAX PERF_REG_RISCV_MAX
#if defined(__riscv_xlen)
#if __riscv_xlen == 64
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
#else
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
#endif
#else
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_NONE
#endif
#endif /* ARCH_PERF_REGS_H */

View file

@ -1,5 +1 @@
perf-util-y += perf_regs.o
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o

View file

@ -1,22 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "perf_regs.h"
#include "../../util/perf_regs.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,58 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */
#include <elfutils/libdwfl.h>
#include "perf_regs.h"
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/sample.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[32];
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_RISCV_##r); \
val; \
})
dwarf_regs[0] = 0;
dwarf_regs[1] = REG(RA);
dwarf_regs[2] = REG(SP);
dwarf_regs[3] = REG(GP);
dwarf_regs[4] = REG(TP);
dwarf_regs[5] = REG(T0);
dwarf_regs[6] = REG(T1);
dwarf_regs[7] = REG(T2);
dwarf_regs[8] = REG(S0);
dwarf_regs[9] = REG(S1);
dwarf_regs[10] = REG(A0);
dwarf_regs[11] = REG(A1);
dwarf_regs[12] = REG(A2);
dwarf_regs[13] = REG(A3);
dwarf_regs[14] = REG(A4);
dwarf_regs[15] = REG(A5);
dwarf_regs[16] = REG(A6);
dwarf_regs[17] = REG(A7);
dwarf_regs[18] = REG(S2);
dwarf_regs[19] = REG(S3);
dwarf_regs[20] = REG(S4);
dwarf_regs[21] = REG(S5);
dwarf_regs[22] = REG(S6);
dwarf_regs[23] = REG(S7);
dwarf_regs[24] = REG(S8);
dwarf_regs[25] = REG(S9);
dwarf_regs[26] = REG(S10);
dwarf_regs[27] = REG(S11);
dwarf_regs[28] = REG(T3);
dwarf_regs[29] = REG(T4);
dwarf_regs[30] = REG(T5);
dwarf_regs[31] = REG(T6);
dwfl_thread_state_register_pc(thread, REG(PC));
return dwfl_thread_state_registers(thread, 0, PERF_REG_RISCV_MAX,
dwarf_regs);
}

View file

@ -1,36 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
static
struct ins_ops *riscv64__associate_ins_ops(struct arch *arch, const char *name)
{
struct ins_ops *ops = NULL;
if (!strncmp(name, "jal", 3) ||
!strncmp(name, "jr", 2) ||
!strncmp(name, "call", 4))
ops = &call_ops;
else if (!strncmp(name, "ret", 3))
ops = &ret_ops;
else if (name[0] == 'j' || name[0] == 'b')
ops = &jump_ops;
else
return NULL;
arch__associate_ins_ops(arch, name, ops);
return ops;
}
static
int riscv64__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
if (!arch->initialized) {
arch->associate_instruction_ops = riscv64__associate_ins_ops;
arch->initialized = true;
arch->objdump.comment_char = '#';
arch->e_machine = EM_RISCV;
arch->e_flags = 0;
}
return 0;
}

View file

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_JITDUMP := 1

View file

@ -3,7 +3,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/s390/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);

View file

@ -1,8 +1,4 @@
perf-util-y += header.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-y += perf_regs.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-y += machine.o
perf-util-y += pmu.o

View file

@ -1,22 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "perf_regs.h"
#include "../../util/perf_regs.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG_END
};
uint64_t arch__intr_reg_mask(void)
{
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}

View file

@ -1,65 +0,0 @@
#include <linux/kernel.h>
#include <elfutils/libdwfl.h>
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/event.h"
#include "../../util/sample.h"
#include "dwarf-regs-table.h"
#include "perf_regs.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[ARRAY_SIZE(s390_dwarf_regs)];
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_S390_##r); \
val; \
})
/*
* For DWARF register mapping details,
* see also perf/arch/s390/include/dwarf-regs-table.h
*/
dwarf_regs[0] = REG(R0);
dwarf_regs[1] = REG(R1);
dwarf_regs[2] = REG(R2);
dwarf_regs[3] = REG(R3);
dwarf_regs[4] = REG(R4);
dwarf_regs[5] = REG(R5);
dwarf_regs[6] = REG(R6);
dwarf_regs[7] = REG(R7);
dwarf_regs[8] = REG(R8);
dwarf_regs[9] = REG(R9);
dwarf_regs[10] = REG(R10);
dwarf_regs[11] = REG(R11);
dwarf_regs[12] = REG(R12);
dwarf_regs[13] = REG(R13);
dwarf_regs[14] = REG(R14);
dwarf_regs[15] = REG(R15);
dwarf_regs[16] = REG(FP0);
dwarf_regs[17] = REG(FP2);
dwarf_regs[18] = REG(FP4);
dwarf_regs[19] = REG(FP6);
dwarf_regs[20] = REG(FP1);
dwarf_regs[21] = REG(FP3);
dwarf_regs[22] = REG(FP5);
dwarf_regs[23] = REG(FP7);
dwarf_regs[24] = REG(FP8);
dwarf_regs[25] = REG(FP10);
dwarf_regs[26] = REG(FP12);
dwarf_regs[27] = REG(FP14);
dwarf_regs[28] = REG(FP9);
dwarf_regs[29] = REG(FP11);
dwarf_regs[30] = REG(FP13);
dwarf_regs[31] = REG(FP15);
dwarf_regs[64] = REG(MASK);
dwarf_regs[65] = REG(PC);
dwfl_thread_state_register_pc(thread, dwarf_regs[65]);
return dwfl_thread_state_registers(thread, 0, 32, dwarf_regs);
}

View file

@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_JITDUMP := 1

View file

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <linux/types.h>
#include <asm/perf_regs.h>
#include "../../../../arch/x86/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);

View file

@ -80,26 +80,24 @@ static int bp_modify1(void)
*/
if (ptrace(PTRACE_POKEUSER, child,
offsetof(struct user, u_debugreg[0]), bp_2)) {
pr_debug("failed to set breakpoint, 1st time: %s\n",
strerror(errno));
pr_debug("failed to set breakpoint, 1st time: %m\n");
goto out;
}
if (ptrace(PTRACE_POKEUSER, child,
offsetof(struct user, u_debugreg[0]), bp_1)) {
pr_debug("failed to set breakpoint, 2nd time: %s\n",
strerror(errno));
pr_debug("failed to set breakpoint, 2nd time: %m\n");
goto out;
}
if (ptrace(PTRACE_POKEUSER, child,
offsetof(struct user, u_debugreg[7]), dr7)) {
pr_debug("failed to set dr7: %s\n", strerror(errno));
pr_debug("failed to set dr7: %m\n");
goto out;
}
if (ptrace(PTRACE_CONT, child, NULL, NULL)) {
pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));
pr_debug("failed to PTRACE_CONT: %m\n");
goto out;
}
@ -112,19 +110,17 @@ static int bp_modify1(void)
rip = ptrace(PTRACE_PEEKUSER, child,
offsetof(struct user_regs_struct, rip), NULL);
if (rip == (unsigned long) -1) {
pr_debug("failed to PTRACE_PEEKUSER: %s\n",
strerror(errno));
pr_debug("failed to PTRACE_PEEKUSER: %m\n");
goto out;
}
pr_debug("rip %lx, bp_1 %p\n", rip, bp_1);
out:
if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));
pr_debug("failed to PTRACE_DETACH: %m\n");
return TEST_FAIL;
}
}
return rip == (unsigned long) bp_1 ? TEST_OK : TEST_FAIL;
}
@ -157,14 +153,13 @@ static int bp_modify2(void)
*/
if (ptrace(PTRACE_POKEUSER, child,
offsetof(struct user, u_debugreg[0]), bp_1)) {
pr_debug("failed to set breakpoint: %s\n",
strerror(errno));
pr_debug("failed to set breakpoint: %m\n");
goto out;
}
if (ptrace(PTRACE_POKEUSER, child,
offsetof(struct user, u_debugreg[7]), dr7)) {
pr_debug("failed to set dr7: %s\n", strerror(errno));
pr_debug("failed to set dr7: %m\n");
goto out;
}
@ -175,7 +170,7 @@ static int bp_modify2(void)
}
if (ptrace(PTRACE_CONT, child, NULL, NULL)) {
pr_debug("failed to PTRACE_CONT: %s\n", strerror(errno));
pr_debug("failed to PTRACE_CONT: %m\n");
goto out;
}
@ -188,8 +183,7 @@ static int bp_modify2(void)
rip = ptrace(PTRACE_PEEKUSER, child,
offsetof(struct user_regs_struct, rip), NULL);
if (rip == (unsigned long) -1) {
pr_debug("failed to PTRACE_PEEKUSER: %s\n",
strerror(errno));
pr_debug("failed to PTRACE_PEEKUSER: %m\n");
goto out;
}
@ -197,7 +191,7 @@ static int bp_modify2(void)
out:
if (ptrace(PTRACE_DETACH, child, NULL, NULL)) {
pr_debug("failed to PTRACE_DETACH: %s", strerror(errno));
pr_debug("failed to PTRACE_DETACH: %m\n");
return TEST_FAIL;
}

View file

@ -1,8 +1,6 @@
perf-util-y += header.o
perf-util-y += tsc.o
perf-util-y += pmu.o
perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o
perf-util-y += perf_regs.o
perf-util-y += topdown.o
perf-util-y += machine.o
perf-util-y += event.o
@ -12,9 +10,7 @@ perf-util-y += evsel.o
perf-util-y += iostat.o
perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
perf-util-y += auxtrace.o
perf-util-y += archinsn.o
perf-util-y += intel-pt.o
perf-util-y += intel-bts.o

View file

@ -1,27 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include "archinsn.h"
#include "event.h"
#include "machine.h"
#include "thread.h"
#include "symbol.h"
#include "../../../../arch/x86/include/asm/insn.h"
void arch_fetch_insn(struct perf_sample *sample,
struct thread *thread,
struct machine *machine)
{
struct insn insn;
int len, ret;
bool is64bit = false;
if (!sample->ip)
return;
len = thread__memcpy(thread, machine, sample->insn, sample->ip, sizeof(sample->insn), &is64bit);
if (len <= 0)
return;
ret = insn_decode(&insn, sample->insn, len,
is64bit ? INSN_MODE_64 : INSN_MODE_32);
if (ret >= 0 && insn.length <= len)
sample->insn_len = insn.length;
}

View file

@ -664,8 +664,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
return 0;
if (opts->auxtrace_sample_mode)
evsel__set_config_if_unset(intel_pt_pmu, intel_pt_evsel,
"psb_period", 0);
evsel__set_config_if_unset(intel_pt_evsel, "psb_period", 0);
err = intel_pt_validate_config(intel_pt_pmu, intel_pt_evsel);
if (err)

View file

@ -1,330 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <string.h>
#include <regex.h>
#include <linux/kernel.h>
#include <linux/zalloc.h>
#include "perf_regs.h"
#include "../../../perf-sys.h"
#include "../../../util/perf_regs.h"
#include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/pmu.h"
#include "../../../util/pmus.h"
static const struct sample_reg sample_reg_masks[] = {
SMPL_REG(AX, PERF_REG_X86_AX),
SMPL_REG(BX, PERF_REG_X86_BX),
SMPL_REG(CX, PERF_REG_X86_CX),
SMPL_REG(DX, PERF_REG_X86_DX),
SMPL_REG(SI, PERF_REG_X86_SI),
SMPL_REG(DI, PERF_REG_X86_DI),
SMPL_REG(BP, PERF_REG_X86_BP),
SMPL_REG(SP, PERF_REG_X86_SP),
SMPL_REG(IP, PERF_REG_X86_IP),
SMPL_REG(FLAGS, PERF_REG_X86_FLAGS),
SMPL_REG(CS, PERF_REG_X86_CS),
SMPL_REG(SS, PERF_REG_X86_SS),
#ifdef HAVE_ARCH_X86_64_SUPPORT
SMPL_REG(R8, PERF_REG_X86_R8),
SMPL_REG(R9, PERF_REG_X86_R9),
SMPL_REG(R10, PERF_REG_X86_R10),
SMPL_REG(R11, PERF_REG_X86_R11),
SMPL_REG(R12, PERF_REG_X86_R12),
SMPL_REG(R13, PERF_REG_X86_R13),
SMPL_REG(R14, PERF_REG_X86_R14),
SMPL_REG(R15, PERF_REG_X86_R15),
#endif
SMPL_REG2(XMM0, PERF_REG_X86_XMM0),
SMPL_REG2(XMM1, PERF_REG_X86_XMM1),
SMPL_REG2(XMM2, PERF_REG_X86_XMM2),
SMPL_REG2(XMM3, PERF_REG_X86_XMM3),
SMPL_REG2(XMM4, PERF_REG_X86_XMM4),
SMPL_REG2(XMM5, PERF_REG_X86_XMM5),
SMPL_REG2(XMM6, PERF_REG_X86_XMM6),
SMPL_REG2(XMM7, PERF_REG_X86_XMM7),
SMPL_REG2(XMM8, PERF_REG_X86_XMM8),
SMPL_REG2(XMM9, PERF_REG_X86_XMM9),
SMPL_REG2(XMM10, PERF_REG_X86_XMM10),
SMPL_REG2(XMM11, PERF_REG_X86_XMM11),
SMPL_REG2(XMM12, PERF_REG_X86_XMM12),
SMPL_REG2(XMM13, PERF_REG_X86_XMM13),
SMPL_REG2(XMM14, PERF_REG_X86_XMM14),
SMPL_REG2(XMM15, PERF_REG_X86_XMM15),
SMPL_REG_END
};
struct sdt_name_reg {
const char *sdt_name;
const char *uprobe_name;
};
#define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
#define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
static const struct sdt_name_reg sdt_reg_tbl[] = {
SDT_NAME_REG(eax, ax),
SDT_NAME_REG(rax, ax),
SDT_NAME_REG(al, ax),
SDT_NAME_REG(ah, ax),
SDT_NAME_REG(ebx, bx),
SDT_NAME_REG(rbx, bx),
SDT_NAME_REG(bl, bx),
SDT_NAME_REG(bh, bx),
SDT_NAME_REG(ecx, cx),
SDT_NAME_REG(rcx, cx),
SDT_NAME_REG(cl, cx),
SDT_NAME_REG(ch, cx),
SDT_NAME_REG(edx, dx),
SDT_NAME_REG(rdx, dx),
SDT_NAME_REG(dl, dx),
SDT_NAME_REG(dh, dx),
SDT_NAME_REG(esi, si),
SDT_NAME_REG(rsi, si),
SDT_NAME_REG(sil, si),
SDT_NAME_REG(edi, di),
SDT_NAME_REG(rdi, di),
SDT_NAME_REG(dil, di),
SDT_NAME_REG(ebp, bp),
SDT_NAME_REG(rbp, bp),
SDT_NAME_REG(bpl, bp),
SDT_NAME_REG(rsp, sp),
SDT_NAME_REG(esp, sp),
SDT_NAME_REG(spl, sp),
/* rNN registers */
SDT_NAME_REG(r8b, r8),
SDT_NAME_REG(r8w, r8),
SDT_NAME_REG(r8d, r8),
SDT_NAME_REG(r9b, r9),
SDT_NAME_REG(r9w, r9),
SDT_NAME_REG(r9d, r9),
SDT_NAME_REG(r10b, r10),
SDT_NAME_REG(r10w, r10),
SDT_NAME_REG(r10d, r10),
SDT_NAME_REG(r11b, r11),
SDT_NAME_REG(r11w, r11),
SDT_NAME_REG(r11d, r11),
SDT_NAME_REG(r12b, r12),
SDT_NAME_REG(r12w, r12),
SDT_NAME_REG(r12d, r12),
SDT_NAME_REG(r13b, r13),
SDT_NAME_REG(r13w, r13),
SDT_NAME_REG(r13d, r13),
SDT_NAME_REG(r14b, r14),
SDT_NAME_REG(r14w, r14),
SDT_NAME_REG(r14d, r14),
SDT_NAME_REG(r15b, r15),
SDT_NAME_REG(r15w, r15),
SDT_NAME_REG(r15d, r15),
SDT_NAME_REG_END,
};
/*
* Perf only supports OP which is in +/-NUM(REG) form.
* Here plus-minus sign, NUM and parenthesis are optional,
* only REG is mandatory.
*
* SDT events also supports indirect addressing mode with a
* symbol as offset, scaled mode and constants in OP. But
* perf does not support them yet. Below are few examples.
*
* OP with scaled mode:
* (%rax,%rsi,8)
* 10(%ras,%rsi,8)
*
* OP with indirect addressing mode:
* check_action(%rip)
* mp_+52(%rip)
* 44+mp_(%rip)
*
* OP with constant values:
* $0
* $123
* $-1
*/
#define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
static regex_t sdt_op_regex;
static int sdt_init_op_regex(void)
{
static int initialized;
int ret = 0;
if (initialized)
return 0;
ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
if (ret < 0) {
pr_debug4("Regex compilation error.\n");
return ret;
}
initialized = 1;
return 0;
}
/*
* Max x86 register name length is 5(ex: %r15d). So, 6th char
* should always contain NULL. This helps to find register name
* length using strlen, instead of maintaining one more variable.
*/
#define SDT_REG_NAME_SIZE 6
/*
* The uprobe parser does not support all gas register names;
* so, we have to replace them (ex. for x86_64: %rax -> %ax).
* Note: If register does not require renaming, just copy
* paste as it is, but don't leave it empty.
*/
static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
{
int i = 0;
for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
return;
}
}
strncpy(uprobe_reg, sdt_reg, sdt_len);
}
int arch_sdt_arg_parse_op(char *old_op, char **new_op)
{
char new_reg[SDT_REG_NAME_SIZE] = {0};
int new_len = 0, ret;
/*
* rm[0]: +/-NUM(REG)
* rm[1]: +/-
* rm[2]: NUM
* rm[3]: (
* rm[4]: REG
* rm[5]: )
*/
regmatch_t rm[6];
/*
* Max prefix length is 2 as it may contains sign(+/-)
* and displacement 0 (Both sign and displacement 0 are
* optional so it may be empty). Use one more character
* to hold last NULL so that strlen can be used to find
* prefix length, instead of maintaining one more variable.
*/
char prefix[3] = {0};
ret = sdt_init_op_regex();
if (ret < 0)
return ret;
/*
* If unsupported OR does not match with regex OR
* register name too long, skip it.
*/
if (strchr(old_op, ',') || strchr(old_op, '$') ||
regexec(&sdt_op_regex, old_op, 6, rm, 0) ||
rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
return SDT_ARG_SKIP;
}
/*
* Prepare prefix.
* If SDT OP has parenthesis but does not provide
* displacement, add 0 for displacement.
* SDT Uprobe Prefix
* -----------------------------
* +24(%rdi) +24(%di) +
* 24(%rdi) +24(%di) +
* %rdi %di
* (%rdi) +0(%di) +0
* -80(%rbx) -80(%bx) -
*/
if (rm[3].rm_so != rm[3].rm_eo) {
if (rm[1].rm_so != rm[1].rm_eo)
prefix[0] = *(old_op + rm[1].rm_so);
else if (rm[2].rm_so != rm[2].rm_eo)
prefix[0] = '+';
else
scnprintf(prefix, sizeof(prefix), "+0");
}
/* Rename register */
sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
new_reg);
/* Prepare final OP which should be valid for uprobe_events */
new_len = strlen(prefix) +
(rm[2].rm_eo - rm[2].rm_so) +
(rm[3].rm_eo - rm[3].rm_so) +
strlen(new_reg) +
(rm[5].rm_eo - rm[5].rm_so) +
1; /* NULL */
*new_op = zalloc(new_len);
if (!*new_op)
return -ENOMEM;
scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
strlen(prefix), prefix,
(int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
(int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
strlen(new_reg), new_reg,
(int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
return SDT_ARG_VALID;
}
const struct sample_reg *arch__sample_reg_masks(void)
{
return sample_reg_masks;
}
uint64_t arch__intr_reg_mask(void)
{
struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_INTR,
.sample_regs_intr = PERF_REG_EXTENDED_MASK,
.precise_ip = 1,
.disabled = 1,
.exclude_kernel = 1,
};
int fd;
/*
* In an unnamed union, init it here to build on older gcc versions
*/
attr.sample_period = 1;
if (perf_pmus__num_core_pmus() > 1) {
struct perf_pmu *pmu = NULL;
__u64 type = PERF_TYPE_RAW;
/*
* The same register set is supported among different hybrid PMUs.
* Only check the first available one.
*/
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
type = pmu->type;
break;
}
attr.config |= type << PERF_PMU_TYPE_SHIFT;
}
event_attr_init(&attr);
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd != -1) {
close(fd);
return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
}
return PERF_REGS_MASK;
}
uint64_t arch__user_reg_mask(void)
{
return PERF_REGS_MASK;
}

View file

@ -1,54 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include "perf_regs.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "util/sample.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
struct unwind_info *ui = arg;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word dwarf_regs[17];
unsigned nregs;
#define REG(r) ({ \
Dwarf_Word val = 0; \
perf_reg_value(&val, user_regs, PERF_REG_X86_##r); \
val; \
})
if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
dwarf_regs[0] = REG(AX);
dwarf_regs[1] = REG(CX);
dwarf_regs[2] = REG(DX);
dwarf_regs[3] = REG(BX);
dwarf_regs[4] = REG(SP);
dwarf_regs[5] = REG(BP);
dwarf_regs[6] = REG(SI);
dwarf_regs[7] = REG(DI);
dwarf_regs[8] = REG(IP);
nregs = 9;
} else {
dwarf_regs[0] = REG(AX);
dwarf_regs[1] = REG(DX);
dwarf_regs[2] = REG(CX);
dwarf_regs[3] = REG(BX);
dwarf_regs[4] = REG(SI);
dwarf_regs[5] = REG(DI);
dwarf_regs[6] = REG(BP);
dwarf_regs[7] = REG(SP);
dwarf_regs[8] = REG(R8);
dwarf_regs[9] = REG(R9);
dwarf_regs[10] = REG(R10);
dwarf_regs[11] = REG(R11);
dwarf_regs[12] = REG(R12);
dwarf_regs[13] = REG(R13);
dwarf_regs[14] = REG(R14);
dwarf_regs[15] = REG(R15);
dwarf_regs[16] = REG(IP);
nregs = 17;
}
return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
}

View file

@ -54,7 +54,7 @@ static const char * const bench_uprobe_usage[] = {
/*opts=*/&uprobe_opts); \
if (!skel->links.prog) { \
err = -errno; \
fprintf(stderr, "Failed to attach bench uprobe \"%s\": %s\n", #prog, strerror(errno)); \
fprintf(stderr, "Failed to attach bench uprobe \"%s\": %m\n", #prog); \
goto cleanup; \
}

View file

@ -43,6 +43,7 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("dwarf_getlocations", HAVE_LIBDW_SUPPORT),
FEATURE_STATUS("dwarf-unwind", HAVE_DWARF_UNWIND_SUPPORT),
FEATURE_STATUS_TIP("libbfd", HAVE_LIBBFD_SUPPORT, "Deprecated, license incompatibility, use BUILD_NONDISTRO=1 and install binutils-dev[el]"),
FEATURE_STATUS("libbabeltrace", HAVE_LIBBABELTRACE_SUPPORT),
FEATURE_STATUS("libbpf-strings", HAVE_LIBBPF_STRINGS_SUPPORT),
FEATURE_STATUS("libcapstone", HAVE_LIBCAPSTONE_SUPPORT),
FEATURE_STATUS("libdw-dwarf-unwind", HAVE_LIBDW_SUPPORT),
@ -60,6 +61,7 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("numa_num_possible_cpus", HAVE_LIBNUMA_SUPPORT),
FEATURE_STATUS("zlib", HAVE_ZLIB_SUPPORT),
FEATURE_STATUS("zstd", HAVE_ZSTD_SUPPORT),
FEATURE_STATUS("rust", HAVE_RUST_SUPPORT),
/* this should remain at end, to know the array end */
FEATURE_STATUS(NULL, _)

View file

@ -265,8 +265,7 @@ static int check_base(struct daemon *daemon)
daemon->base);
return -EACCES;
default:
pr_err("failed: can't access base '%s': %s\n",
daemon->base, strerror(errno));
pr_err("failed: can't access base '%s': %m\n", daemon->base);
return -errno;
}
}
@ -544,8 +543,7 @@ static int daemon_session__control(struct daemon_session *session,
err = writen(control, msg, len);
if (err != len) {
pr_err("failed: write to control pipe: %d (%s)\n",
errno, control_path);
pr_err("failed: write to control pipe: %m (%s)\n", control_path);
goto out;
}
@ -586,7 +584,7 @@ static int setup_server_socket(struct daemon *daemon)
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "socket: %s\n", strerror(errno));
fprintf(stderr, "socket: %m\n");
return -1;
}

View file

@ -33,6 +33,7 @@ const char *to_ctf;
struct perf_data_convert_opts opts = {
.force = false,
.all = false,
.time_str = NULL,
};
const struct option data_options[] = {
@ -45,6 +46,8 @@ const struct option data_options[] = {
#endif
OPT_BOOLEAN('f', "force", &opts.force, "don't complain, do it"),
OPT_BOOLEAN(0, "all", &opts.all, "Convert all events"),
OPT_STRING(0, "time", &opts.time_str, "str",
"Time span of interest (start,stop)"),
OPT_END()
};

View file

@ -178,10 +178,9 @@ static struct header_column {
}
};
static int setup_compute_opt_wdiff(char *opt)
static int setup_compute_opt_wdiff(const char *opt)
{
char *w1_str = opt;
char *w2_str;
const char *w1_str = opt, *w2_str;
int ret = -EINVAL;
@ -192,8 +191,7 @@ static int setup_compute_opt_wdiff(char *opt)
if (!w2_str)
goto out;
*w2_str++ = 0x0;
if (!*w2_str)
if (!*++w2_str)
goto out;
compute_wdiff_w1 = strtol(w1_str, NULL, 10);
@ -214,7 +212,7 @@ static int setup_compute_opt_wdiff(char *opt)
return ret;
}
static int setup_compute_opt(char *opt)
static int setup_compute_opt(const char *opt)
{
if (compute == COMPUTE_WEIGHTED_DIFF)
return setup_compute_opt_wdiff(opt);
@ -234,7 +232,7 @@ static int setup_compute(const struct option *opt, const char *str,
char *cstr = (char *) str;
char buf[50];
unsigned i;
char *option;
const char *option;
if (!str) {
*cp = COMPUTE_DELTA;

View file

@ -9,7 +9,6 @@
#include "util/strbuf.h"
#include "builtin.h"
#include <subcmd/exec-cmd.h>
#include "common-cmds.h"
#include <subcmd/parse-options.h>
#include <subcmd/run-command.h>
#include <subcmd/help.h>
@ -301,16 +300,58 @@ static struct cmdnames main_cmds, other_cmds;
void list_common_cmds_help(void)
{
unsigned int i, longest = 0;
const struct cmdname_help {
const char *name;
const char *help;
} common_cmds[] = {
{"annotate", "Read perf.data (created by perf record) and display annotated code"},
{"archive",
"Create archive with object files with build-ids found in perf.data file"},
{"bench", "General framework for benchmark suites"},
{"buildid-cache", "Manage build-id cache."},
{"buildid-list", "List the buildids in a perf.data file"},
{"c2c", "Shared Data C2C/HITM Analyzer."},
{"config", "Get and set variables in a configuration file."},
{"daemon", "Run record sessions on background"},
{"data", "Data file related processing"},
{"diff", "Read perf.data files and display the differential profile"},
{"evlist", "List the event names in a perf.data file"},
{"ftrace", "simple wrapper for kernel's ftrace functionality"},
{"inject", "Filter to augment the events stream with additional information"},
{"iostat", "Show I/O performance metrics"},
{"kallsyms", "Searches running kernel for symbols"},
{"kvm", "Tool to trace/measure kvm guest os"},
{"list", "List all symbolic event types"},
{"mem", "Profile memory accesses"},
{"record", "Run a command and record its profile into perf.data"},
{"report", "Read perf.data (created by perf record) and display the profile"},
{"script", "Read perf.data (created by perf record) and display trace output"},
{"stat", "Run a command and gather performance counter statistics"},
{"test", "Runs sanity tests."},
{"top", "System profiling tool."},
{"version", "display the version of perf binary"},
#ifdef HAVE_LIBELF_SUPPORT
{"probe", "Define new dynamic tracepoints"},
#endif /* HAVE_LIBELF_SUPPORT */
#ifdef HAVE_LIBTRACEEVENT
{"trace", "strace inspired tool"},
{"kmem", "Tool to trace/measure kernel memory properties"},
{"kwork", "Tool to trace/measure kernel work properties (latencies)"},
{"lock", "Analyze lock events"},
{"sched", "Tool to trace/measure scheduler properties (latencies)"},
{"timechart", "Tool to visualize total system behavior during a workload"},
#endif /* HAVE_LIBTRACEEVENT */
};
size_t longest = 0;
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
for (size_t i = 0; i < ARRAY_SIZE(common_cmds); i++) {
if (longest < strlen(common_cmds[i].name))
longest = strlen(common_cmds[i].name);
}
puts(" The most commonly used perf commands are:");
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
printf(" %-*s ", longest, common_cmds[i].name);
for (size_t i = 0; i < ARRAY_SIZE(common_cmds); i++) {
printf(" %-*s ", (int)longest, common_cmds[i].name);
puts(common_cmds[i].help);
}
}

View file

@ -122,6 +122,7 @@ struct perf_inject {
bool in_place_update;
bool in_place_update_dry_run;
bool copy_kcore_dir;
bool convert_callchain;
const char *input_name;
struct perf_data output;
u64 bytes_written;
@ -133,6 +134,7 @@ struct perf_inject {
struct guest_session guest_session;
struct strlist *known_build_ids;
const struct evsel *mmap_evsel;
struct ip_callchain *raw_callchain;
};
struct event_entry {
@ -383,6 +385,90 @@ static int perf_event__repipe_sample(const struct perf_tool *tool,
return perf_event__repipe_synth(tool, event);
}
static int perf_event__convert_sample_callchain(const struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
struct machine *machine)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
struct callchain_cursor *cursor = get_tls_callchain_cursor();
union perf_event *event_copy = (void *)inject->event_copy;
struct callchain_cursor_node *node;
struct thread *thread;
u64 sample_type = evsel->core.attr.sample_type;
u32 sample_size = event->header.size;
u64 i, k;
int ret;
if (event_copy == NULL) {
inject->event_copy = malloc(PERF_SAMPLE_MAX_SIZE);
if (!inject->event_copy)
return -ENOMEM;
event_copy = (void *)inject->event_copy;
}
if (cursor == NULL)
return -ENOMEM;
callchain_cursor_reset(cursor);
thread = machine__find_thread(machine, sample->tid, sample->pid);
if (thread == NULL)
goto out;
/* this will parse DWARF using stack and register data */
ret = thread__resolve_callchain(thread, cursor, evsel, sample,
/*parent=*/NULL, /*root_al=*/NULL,
PERF_MAX_STACK_DEPTH);
thread__put(thread);
if (ret != 0)
goto out;
/* copy kernel callchain and context entries */
for (i = 0; i < sample->callchain->nr; i++) {
inject->raw_callchain->ips[i] = sample->callchain->ips[i];
if (sample->callchain->ips[i] == PERF_CONTEXT_USER) {
i++;
break;
}
}
if (i == 0 || inject->raw_callchain->ips[i - 1] != PERF_CONTEXT_USER)
inject->raw_callchain->ips[i++] = PERF_CONTEXT_USER;
node = cursor->first;
for (k = 0; k < cursor->nr && i < PERF_MAX_STACK_DEPTH; k++) {
if (machine__kernel_ip(machine, node->ip))
/* kernel IPs were added already */;
else if (node->ms.sym && node->ms.sym->inlined)
/* we can't handle inlined callchains */;
else
inject->raw_callchain->ips[i++] = node->ip;
node = node->next;
}
inject->raw_callchain->nr = i;
sample->callchain = inject->raw_callchain;
out:
memcpy(event_copy, event, sizeof(event->header));
/* adjust sample size for stack and regs */
sample_size -= sample->user_stack.size;
sample_size -= (hweight64(evsel->core.attr.sample_regs_user) + 1) * sizeof(u64);
sample_size += (sample->callchain->nr + 1) * sizeof(u64);
event_copy->header.size = sample_size;
/* remove sample_type {STACK,REGS}_USER for synthesize */
sample_type &= ~(PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER);
perf_event__synthesize_sample(event_copy, sample_type,
evsel->core.attr.read_format, sample);
return perf_event__repipe_synth(tool, event_copy);
}
static struct dso *findnew_dso(int pid, int tid, const char *filename,
const struct dso_id *id, struct machine *machine)
{
@ -2022,7 +2108,7 @@ static int save_section_info(struct perf_inject *inject)
return perf_header__process_sections(header, fd, inject, save_section_info_cb);
}
static bool keep_feat(int feat)
static bool keep_feat(struct perf_inject *inject, int feat)
{
switch (feat) {
/* Keep original information that describes the machine or software */
@ -2047,9 +2133,11 @@ static bool keep_feat(int feat)
case HEADER_CLOCK_DATA:
case HEADER_HYBRID_TOPOLOGY:
case HEADER_PMU_CAPS:
case HEADER_CPU_DOMAIN_INFO:
return true;
/* Information that can be updated */
case HEADER_BUILD_ID:
return inject->build_id_style == BID_RWS__NONE;
case HEADER_CMDLINE:
case HEADER_EVENT_DESC:
case HEADER_BRANCH_STACK:
@ -2108,7 +2196,7 @@ static int feat_copy_cb(struct feat_copier *fc, int feat, struct feat_writer *fw
int ret;
if (!inject->secs[feat].offset ||
!keep_feat(feat))
!keep_feat(inject, feat))
return 0;
ret = feat_copy(inject, feat, fw);
@ -2269,6 +2357,15 @@ static int __cmd_inject(struct perf_inject *inject)
/* Allow space in the header for guest attributes */
output_data_offset += gs->session->header.data_offset;
output_data_offset = roundup(output_data_offset, 4096);
} else if (inject->convert_callchain) {
inject->tool.sample = perf_event__convert_sample_callchain;
inject->tool.fork = perf_event__repipe_fork;
inject->tool.comm = perf_event__repipe_comm;
inject->tool.exit = perf_event__repipe_exit;
inject->tool.mmap = perf_event__repipe_mmap;
inject->tool.mmap2 = perf_event__repipe_mmap2;
inject->tool.ordered_events = true;
inject->tool.ordering_requires_timestamps = true;
}
if (!inject->itrace_synth_opts.set)
@ -2321,6 +2418,23 @@ static int __cmd_inject(struct perf_inject *inject)
perf_header__set_feat(&session->header,
HEADER_BRANCH_STACK);
}
/*
* The converted data file won't have stack and registers.
* Update the perf_event_attr to remove them before writing.
*/
if (inject->convert_callchain) {
struct evsel *evsel;
evlist__for_each_entry(session->evlist, evsel) {
evsel__reset_sample_bit(evsel, REGS_USER);
evsel__reset_sample_bit(evsel, STACK_USER);
evsel->core.attr.sample_regs_user = 0;
evsel->core.attr.sample_stack_user = 0;
evsel->core.attr.exclude_callchain_user = 0;
}
}
session->header.data_offset = output_data_offset;
session->header.data_size = inject->bytes_written;
perf_session__inject_header(session, session->evlist, fd, &inj_fc.fc,
@ -2345,6 +2459,18 @@ static int __cmd_inject(struct perf_inject *inject)
return ret;
}
static bool evsel__has_dwarf_callchain(struct evsel *evsel)
{
struct perf_event_attr *attr = &evsel->core.attr;
const u64 dwarf_callchain_flags =
PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_CALLCHAIN;
if (!attr->exclude_callchain_user)
return false;
return (attr->sample_type & dwarf_callchain_flags) == dwarf_callchain_flags;
}
int cmd_inject(int argc, const char **argv)
{
struct perf_inject inject = {
@ -2413,6 +2539,8 @@ int cmd_inject(int argc, const char **argv)
OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
"guest mount directory under which every guest os"
" instance has a subdir"),
OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
"Generate callchains using DWARF and drop register/stack data"),
OPT_END()
};
const char * const inject_usage[] = {
@ -2428,6 +2556,9 @@ int cmd_inject(int argc, const char **argv)
#ifndef HAVE_JITDUMP
set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
#endif
#ifndef HAVE_LIBDW_SUPPORT
set_option_nobuild(options, 0, "convert-callchain", "NO_LIBDW=1", true);
#endif
argc = parse_options(argc, argv, options, inject_usage, 0);
@ -2526,6 +2657,8 @@ int cmd_inject(int argc, const char **argv)
inject.tool.compressed = perf_event__repipe_op4_synth;
inject.tool.auxtrace = perf_event__repipe_auxtrace;
inject.tool.bpf_metadata = perf_event__repipe_op2_synth;
inject.tool.schedstat_cpu = perf_event__repipe_op2_synth;
inject.tool.schedstat_domain = perf_event__repipe_op2_synth;
inject.tool.dont_split_sample_group = true;
inject.tool.merge_deferred_callchains = false;
inject.session = __perf_session__new(&data, &inject.tool,
@ -2587,6 +2720,28 @@ int cmd_inject(int argc, const char **argv)
}
}
if (inject.convert_callchain) {
struct evsel *evsel;
if (inject.output.is_pipe || inject.session->data->is_pipe) {
pr_err("--convert-callchain cannot work with pipe\n");
goto out_delete;
}
evlist__for_each_entry(inject.session->evlist, evsel) {
if (!evsel__has_dwarf_callchain(evsel) && !evsel__is_dummy_event(evsel)) {
pr_err("--convert-callchain requires DWARF call graph.\n");
goto out_delete;
}
}
inject.raw_callchain = calloc(PERF_MAX_STACK_DEPTH, sizeof(u64));
if (inject.raw_callchain == NULL) {
pr_err("callchain allocation failed\n");
goto out_delete;
}
}
#ifdef HAVE_JITDUMP
if (inject.jit_mode) {
inject.tool.mmap2 = perf_event__repipe_mmap2;
@ -2617,5 +2772,6 @@ out_close_output:
free(inject.itrace_synth_opts.vm_tm_corr_args);
free(inject.event_copy);
free(inject.guest_session.ev.event_buf);
free(inject.raw_callchain);
return ret;
}

View file

@ -2,6 +2,7 @@
#include "builtin.h"
#include "perf.h"
#include <dwarf-regs.h>
#include "util/build-id.h"
#include "util/evsel.h"
#include "util/evlist.h"
@ -52,7 +53,7 @@
#include <math.h>
#include <perf/mmap.h>
#if defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
#if defined(HAVE_LIBTRACEEVENT)
#define GET_EVENT_KEY(func, field) \
static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \
{ \
@ -597,7 +598,7 @@ static void kvm_display(struct perf_kvm_stat *kvm)
#endif /* HAVE_SLANG_SUPPORT */
#endif // defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
#endif // defined(HAVE_LIBTRACEEVENT)
static const char *get_filename_for_perf_kvm(void)
{
@ -613,13 +614,13 @@ static const char *get_filename_for_perf_kvm(void)
return filename;
}
#if defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
#if defined(HAVE_LIBTRACEEVENT)
static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
static bool register_kvm_events_ops(struct perf_kvm_stat *kvm, uint16_t e_machine)
{
struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops;
const struct kvm_reg_events_ops *events_ops;
for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) {
for (events_ops = kvm_reg_events_ops(e_machine); events_ops->name; events_ops++) {
if (!strcmp(events_ops->name, kvm->report_event)) {
kvm->events_ops = events_ops->ops;
return true;
@ -809,7 +810,7 @@ static bool is_child_event(struct perf_kvm_stat *kvm,
struct perf_sample *sample,
struct event_key *key)
{
struct child_event_ops *child_ops;
const struct child_event_ops *child_ops;
child_ops = kvm->events_ops->child_ops;
@ -841,11 +842,11 @@ static bool handle_child_event(struct perf_kvm_stat *kvm,
return true;
}
static bool skip_event(const char *event)
static bool skip_event(uint16_t e_machine, const char *event)
{
const char * const *skip_events;
for (skip_events = kvm_skip_events; *skip_events; skip_events++)
for (skip_events = kvm_skip_events(e_machine); *skip_events; skip_events++)
if (!strcmp(event, *skip_events))
return true;
@ -901,9 +902,10 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
if (kvm->duration && time_diff > kvm->duration) {
char decode[KVM_EVENT_NAME_LEN];
uint16_t e_machine = perf_session__e_machine(kvm->session, /*e_flags=*/NULL);
kvm->events_ops->decode_key(kvm, &event->key, decode);
if (!skip_event(decode)) {
if (!skip_event(e_machine, decode)) {
pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
sample->time, sample->pid, vcpu_record->vcpu_id,
decode, time_diff / NSEC_PER_USEC);
@ -921,6 +923,8 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
/* Only kvm_entry records vcpu id. */
if (!thread__priv(thread) && kvm_entry_event(evsel)) {
struct vcpu_event_record *vcpu_record;
struct machine *machine = maps__machine(thread__maps(thread));
uint16_t e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL);
vcpu_record = zalloc(sizeof(*vcpu_record));
if (!vcpu_record) {
@ -928,7 +932,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
return NULL;
}
vcpu_record->vcpu_id = evsel__intval(evsel, sample, vcpu_id_str);
vcpu_record->vcpu_id = evsel__intval(evsel, sample, vcpu_id_str(e_machine));
thread__set_priv(thread, vcpu_record);
}
@ -1163,6 +1167,7 @@ static int cpu_isa_config(struct perf_kvm_stat *kvm)
{
char buf[128], *cpuid;
int err;
uint16_t e_machine;
if (kvm->live) {
struct perf_cpu cpu = {-1};
@ -1182,7 +1187,8 @@ static int cpu_isa_config(struct perf_kvm_stat *kvm)
return -EINVAL;
}
err = cpu_isa_init(kvm, cpuid);
e_machine = perf_session__e_machine(kvm->session, /*e_flags=*/NULL);
err = cpu_isa_init(kvm, e_machine, cpuid);
if (err == -ENOTSUP)
pr_err("CPU %s is not supported.\n", cpuid);
@ -1413,7 +1419,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
if (!verify_vcpu(kvm->trace_vcpu) ||
!is_valid_key(kvm) ||
!register_kvm_events_ops(kvm)) {
!register_kvm_events_ops(kvm, EM_HOST)) {
goto out;
}
@ -1543,7 +1549,7 @@ out:
static int read_events(struct perf_kvm_stat *kvm)
{
int ret;
uint16_t e_machine;
struct perf_data file = {
.path = kvm->file_name,
.mode = PERF_DATA_MODE_READ,
@ -1568,6 +1574,12 @@ static int read_events(struct perf_kvm_stat *kvm)
goto out_delete;
}
e_machine = perf_session__e_machine(kvm->session, /*e_flags=*/NULL);
if (!register_kvm_events_ops(kvm, e_machine)) {
ret = -EINVAL;
goto out_delete;
}
/*
* Do not use 'isa' recorded in kvm_exit tracepoint since it is not
* traced in the old kernel.
@ -1610,9 +1622,6 @@ static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
if (!is_valid_key(kvm))
goto exit;
if (!register_kvm_events_ops(kvm))
goto exit;
if (kvm->use_stdio) {
use_browser = 0;
setup_pager();
@ -1636,11 +1645,6 @@ exit:
return ret;
}
int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)
{
return 0;
}
static int
kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
{
@ -1658,15 +1662,16 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
};
const char * const *events_tp;
int ret;
uint16_t e_machine = EM_HOST;
events_tp_size = 0;
ret = setup_kvm_events_tp(kvm);
ret = setup_kvm_events_tp(kvm, e_machine);
if (ret < 0) {
pr_err("Unable to setup the kvm tracepoints\n");
return ret;
}
for (events_tp = kvm_events_tp; *events_tp; events_tp++)
for (events_tp = kvm_events_tp(e_machine); *events_tp; events_tp++)
events_tp_size++;
rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
@ -1681,7 +1686,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
for (j = 0; j < events_tp_size; j++) {
rec_argv[i++] = STRDUP_FAIL_EXIT("-e");
rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp(e_machine)[j]);
}
rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
@ -1775,7 +1780,7 @@ static struct evlist *kvm_live_event_list(void)
if (evlist == NULL)
return NULL;
for (events_tp = kvm_events_tp; *events_tp; events_tp++) {
for (events_tp = kvm_events_tp(EM_HOST); *events_tp; events_tp++) {
tp = strdup(*events_tp);
if (tp == NULL)
@ -1900,7 +1905,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
/*
* generate the event list
*/
err = setup_kvm_events_tp(kvm);
err = setup_kvm_events_tp(kvm, EM_HOST);
if (err < 0) {
pr_err("Unable to setup the kvm tracepoints\n");
return err;
@ -1985,13 +1990,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
perf_stat:
return cmd_stat(argc, argv);
}
#endif /* HAVE_KVM_STAT_SUPPORT */
int __weak kvm_add_default_arch_event(int *argc __maybe_unused,
const char **argv __maybe_unused)
{
return 0;
}
#endif /* HAVE_LIBTRACEEVENT */
static int __cmd_record(const char *file_name, int argc, const char **argv)
{
@ -2016,7 +2015,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv)
BUG_ON(i + 2 != rec_argc);
ret = kvm_add_default_arch_event(&i, rec_argv);
ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv);
if (ret)
goto EXIT;
@ -2103,7 +2102,7 @@ static int __cmd_top(int argc, const char **argv)
BUG_ON(i != argc);
ret = kvm_add_default_arch_event(&i, rec_argv);
ret = kvm_add_default_arch_event(EM_HOST, &i, rec_argv);
if (ret)
goto EXIT;
@ -2179,7 +2178,7 @@ int cmd_kvm(int argc, const char **argv)
return __cmd_top(argc, argv);
else if (strlen(argv[0]) > 2 && strstarts("buildid-list", argv[0]))
return __cmd_buildid_list(file_name, argc, argv);
#if defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
#if defined(HAVE_LIBTRACEEVENT)
else if (strlen(argv[0]) > 2 && strstarts("stat", argv[0]))
return kvm_cmd_stat(file_name, argc, argv);
#endif

View file

@ -648,7 +648,7 @@ int cmd_list(int argc, const char **argv)
}
for (i = 0; i < argc; ++i) {
char *sep, *s;
char *s;
if (strcmp(argv[i], "tracepoint") == 0) {
char *old_pmu_glob = default_ps.pmu_glob;
@ -720,7 +720,7 @@ int cmd_list(int argc, const char **argv)
else if (strcmp(argv[i], "pfm") == 0)
print_libpfm_events(&print_cb, ps);
#endif
else if ((sep = strchr(argv[i], ':')) != NULL) {
else if (strchr(argv[i], ':') != NULL) {
char *old_pmu_glob = ps->pmu_glob;
char *old_event_glob = ps->event_glob;

View file

@ -211,8 +211,7 @@ static int opt_set_target_ns(const struct option *opt __maybe_unused,
ns_pid = (pid_t)strtol(str, NULL, 10);
if (errno != 0) {
ret = -errno;
pr_warning("Failed to parse %s as a pid: %s\n", str,
strerror(errno));
pr_warning("Failed to parse %s as a pid: %m\n", str);
return ret;
}
nsip = nsinfo__new(ns_pid);

View file

@ -1286,7 +1286,6 @@ static int record__mmap_evlist(struct record *rec,
struct record_opts *opts = &rec->opts;
bool auxtrace_overwrite = opts->auxtrace_snapshot_mode ||
opts->auxtrace_sample_mode;
char msg[512];
if (opts->affinity != PERF_AFFINITY_SYS)
cpu__setup_cpunode_map();
@ -1305,8 +1304,7 @@ static int record__mmap_evlist(struct record *rec,
opts->mmap_pages, opts->auxtrace_mmap_pages);
return -errno;
} else {
pr_err("failed to mmap with %d (%s)\n", errno,
str_error_r(errno, msg, sizeof(msg)));
pr_err("failed to mmap: %m\n");
if (errno)
return -errno;
else
@ -1324,7 +1322,8 @@ static int record__mmap_evlist(struct record *rec,
if (record__threads_enabled(rec)) {
ret = perf_data__create_dir(&rec->data, evlist->core.nr_mmaps);
if (ret) {
pr_err("Failed to create data directory: %s\n", strerror(-ret));
errno = -ret;
pr_err("Failed to create data directory: %m\n");
return ret;
}
for (i = 0; i < evlist->core.nr_mmaps; i++) {
@ -1404,6 +1403,7 @@ try_again:
}
#endif
if (report_error || verbose > 0) {
evsel__open_strerror(pos, &opts->target, errno, msg, sizeof(msg));
ui__error("Failure to open event '%s' on PMU '%s' which will be "
"removed.\n%s\n",
evsel__name(pos), evsel__pmu_name(pos), msg);
@ -1461,9 +1461,8 @@ try_again:
}
if (evlist__apply_filters(evlist, &pos, &opts->target)) {
pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n",
pos->filter ?: "BPF", evsel__name(pos), errno,
str_error_r(errno, msg, sizeof(msg)));
pr_err("failed to set filter \"%s\" on event %s: %m\n",
pos->filter ?: "BPF", evsel__name(pos));
rc = -1;
goto out;
}
@ -1511,6 +1510,8 @@ static int process_buildids(struct record *rec)
if (perf_data__size(&rec->data) == 0)
return 0;
/* A single DSO is needed and not all inline frames. */
symbol_conf.inline_name = false;
/*
* During this process, it'll load kernel map and replace the
* dso->long_name to a real pathname it found. In this case
@ -1521,7 +1522,6 @@ static int process_buildids(struct record *rec)
* $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
*/
symbol_conf.ignore_vmlinux_buildid = true;
/*
* If --buildid-all is given, it marks all DSO regardless of hits,
* so no need to process samples. But if timestamp_boundary is enabled,
@ -1748,8 +1748,7 @@ static void *record__thread(void *arg)
err = write(thread->pipes.ack[1], &msg, sizeof(msg));
if (err == -1)
pr_warning("threads[%d]: failed to notify on start: %s\n",
thread->tid, strerror(errno));
pr_warning("threads[%d]: failed to notify on start: %m\n", thread->tid);
pr_debug("threads[%d]: started on cpu%d\n", thread->tid, sched_getcpu());
@ -1792,8 +1791,7 @@ static void *record__thread(void *arg)
err = write(thread->pipes.ack[1], &msg, sizeof(msg));
if (err == -1)
pr_warning("threads[%d]: failed to notify on termination: %s\n",
thread->tid, strerror(errno));
pr_warning("threads[%d]: failed to notify on termination: %m\n", thread->tid);
return NULL;
}
@ -1881,7 +1879,7 @@ static int record__synthesize_workload(struct record *rec, bool tail)
process_synthesized_event,
&rec->session->machines.host,
needs_mmap,
rec->opts.sample_address);
rec->opts.record_data_mmap);
perf_thread_map__put(thread_map);
return err;
}
@ -2191,7 +2189,7 @@ static int record__synthesize(struct record *rec, bool tail)
err = __machine__synthesize_threads(machine, tool, &opts->target,
rec->evlist->core.threads,
f, needs_mmap, opts->sample_address,
f, needs_mmap, opts->record_data_mmap,
rec->opts.nr_threads_synthesize);
}
@ -2338,7 +2336,7 @@ static int record__start_threads(struct record *rec)
sigfillset(&full);
if (sigprocmask(SIG_SETMASK, &full, &mask)) {
pr_err("Failed to block signals on threads start: %s\n", strerror(errno));
pr_err("Failed to block signals on threads start: %m\n");
return -1;
}
@ -2356,7 +2354,7 @@ static int record__start_threads(struct record *rec)
if (pthread_create(&handle, &attrs, record__thread, &thread_data[t])) {
for (tt = 1; tt < t; tt++)
record__terminate_thread(&thread_data[t]);
pr_err("Failed to start threads: %s\n", strerror(errno));
pr_err("Failed to start threads: %m\n");
ret = -1;
goto out_err;
}
@ -2379,7 +2377,7 @@ out_err:
pthread_attr_destroy(&attrs);
if (sigprocmask(SIG_SETMASK, &mask, NULL)) {
pr_err("Failed to unblock signals on threads start: %s\n", strerror(errno));
pr_err("Failed to unblock signals on threads start: %m\n");
ret = -1;
}
@ -3006,8 +3004,9 @@ int record_opts__parse_callchain(struct record_opts *record,
ret = parse_callchain_record_opt(arg, callchain);
if (!ret) {
/* Enable data address sampling for DWARF unwind. */
if (callchain->record_mode == CALLCHAIN_DWARF)
record->sample_address = true;
if (callchain->record_mode == CALLCHAIN_DWARF &&
!record->record_data_mmap_set)
record->record_data_mmap = true;
callchain_debug(callchain);
}
@ -3686,6 +3685,9 @@ static struct option __record_options[] = {
OPT_CALLBACK(0, "off-cpu-thresh", &record.opts, "ms",
"Dump off-cpu samples if off-cpu time exceeds this threshold (in milliseconds). (Default: 500ms)",
record__parse_off_cpu_thresh),
OPT_BOOLEAN_SET(0, "data-mmap", &record.opts.record_data_mmap,
&record.opts.record_data_mmap_set,
"Record mmap events for non-executable mappings"),
OPT_END()
};
@ -4249,9 +4251,12 @@ int cmd_record(int argc, const char **argv)
goto out_opts;
}
/* For backward compatibility, -d implies --mem-info */
if (rec->opts.sample_address)
/* For backward compatibility, -d implies --mem-info and --data-mmap */
if (rec->opts.sample_address) {
rec->opts.sample_data_src = true;
if (!rec->opts.record_data_mmap_set)
rec->opts.record_data_mmap = true;
}
/*
* Allow aliases to facilitate the lookup of symbols for address

View file

@ -448,7 +448,7 @@ static int report__setup_sample_type(struct report *rep)
}
}
callchain_param_setup(sample_type, perf_env__arch(perf_session__env(rep->session)));
callchain_param_setup(sample_type, perf_session__e_machine(session, /*e_flags=*/NULL));
if (rep->stitch_lbr && (callchain_param.record_mode != CALLCHAIN_LBR)) {
ui__warning("Can't find LBR callchain. Switch off --stitch-lbr.\n"
@ -1271,12 +1271,18 @@ parse_percent_limit(const struct option *opt, const char *str,
return 0;
}
static int
report_parse_addr2line_config(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused)
{
return addr2line_configure("addr2line.style", arg, NULL);
}
static int process_attr(const struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct evlist **pevlist)
{
struct perf_session *session;
struct perf_env *env;
u64 sample_type;
int err;
@ -1290,8 +1296,7 @@ static int process_attr(const struct perf_tool *tool __maybe_unused,
*/
sample_type = evlist__combined_sample_type(*pevlist);
session = (*pevlist)->session;
env = perf_session__env(session);
callchain_param_setup(sample_type, perf_env__arch(env));
callchain_param_setup(sample_type, perf_session__e_machine(session, /*e_flags=*/NULL));
return 0;
}
@ -1447,6 +1452,9 @@ int cmd_report(int argc, const char **argv)
"objdump binary to use for disassembly and annotations"),
OPT_STRING(0, "addr2line", &addr2line_path, "path",
"addr2line binary to use for line numbers"),
OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
"addr2line styles (libdw,llvm,libbfd,addr2line)",
report_parse_addr2line_config),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Symbol demangling. Enabled by default, use --no-demangle to disable."),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
@ -1727,7 +1735,8 @@ repeat:
sort_order = NULL;
}
if (sort_order && strstr(sort_order, "type")) {
if ((sort_order && strstr(sort_order, "type")) ||
(field_order && strstr(field_order, "type"))) {
report.data_type = true;
annotate_opts.annotate_src = false;

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,6 @@
#include "ui/ui.h"
#include "print_binary.h"
#include "print_insn.h"
#include "archinsn.h"
#include <linux/bitmap.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
@ -90,7 +89,6 @@ static bool print_flags;
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
static int max_blocks;
static bool native_arch;
static struct dlfilter *dlfilter;
static int dlargc;
static char **dlargv;
@ -717,7 +715,8 @@ out:
return 0;
}
static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, const char *arch,
static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask,
uint16_t e_machine, uint32_t e_flags,
FILE *fp)
{
unsigned i = 0, r;
@ -730,7 +729,9 @@ static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask, cons
for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {
u64 val = regs->regs[i++];
printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r, arch), val);
printed += fprintf(fp, "%5s:0x%"PRIx64" ",
perf_reg_name(r, e_machine, e_flags),
val);
}
return printed;
@ -787,23 +788,29 @@ tod_scnprintf(struct perf_script *script, char *buf, int buflen,
}
static int perf_sample__fprintf_iregs(struct perf_sample *sample,
struct perf_event_attr *attr, const char *arch, FILE *fp)
struct perf_event_attr *attr,
uint16_t e_machine,
uint32_t e_flags,
FILE *fp)
{
if (!sample->intr_regs)
return 0;
return perf_sample__fprintf_regs(perf_sample__intr_regs(sample),
attr->sample_regs_intr, arch, fp);
attr->sample_regs_intr, e_machine, e_flags, fp);
}
static int perf_sample__fprintf_uregs(struct perf_sample *sample,
struct perf_event_attr *attr, const char *arch, FILE *fp)
struct perf_event_attr *attr,
uint16_t e_machine,
uint32_t e_flags,
FILE *fp)
{
if (!sample->user_regs)
return 0;
return perf_sample__fprintf_regs(perf_sample__user_regs(sample),
attr->sample_regs_user, arch, fp);
attr->sample_regs_user, e_machine, e_flags, fp);
}
static int perf_sample__fprintf_start(struct perf_script *script,
@ -1618,7 +1625,7 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample,
{
int printed = 0;
script_fetch_insn(sample, thread, machine, native_arch);
perf_sample__fetch_insn(sample, thread, machine);
if (PRINT_FIELD(INSNLEN))
printed += fprintf(fp, " ilen: %d", sample->insn_len);
@ -2418,7 +2425,7 @@ static void process_event(struct perf_script *script,
struct evsel_script *es = evsel->priv;
FILE *fp = es->fp;
char str[PAGE_SIZE_NAME_LEN];
const char *arch = perf_env__arch(machine->env);
uint32_t e_flags;
if (output[type].fields == 0)
return;
@ -2505,11 +2512,19 @@ static void process_event(struct perf_script *script,
symbol_conf.bt_stop_list, fp);
}
if (PRINT_FIELD(IREGS))
perf_sample__fprintf_iregs(sample, attr, arch, fp);
if (PRINT_FIELD(IREGS)) {
perf_sample__fprintf_iregs(sample, attr,
thread__e_machine(thread, machine, &e_flags),
e_flags,
fp);
}
if (PRINT_FIELD(UREGS))
perf_sample__fprintf_uregs(sample, attr, arch, fp);
if (PRINT_FIELD(UREGS)) {
perf_sample__fprintf_uregs(sample, attr,
thread__e_machine(thread, machine, &e_flags),
e_flags,
fp);
}
if (PRINT_FIELD(BRSTACK))
perf_sample__fprintf_brstack(sample, thread, evsel, fp);
@ -2803,6 +2818,7 @@ static int process_attr(const struct perf_tool *tool, union perf_event *event,
struct perf_script *scr = container_of(tool, struct perf_script, tool);
struct evlist *evlist;
struct evsel *evsel, *pos;
uint16_t e_machine;
u64 sample_type;
int err;
@ -2844,7 +2860,8 @@ static int process_attr(const struct perf_tool *tool, union perf_event *event,
* on events sample_type.
*/
sample_type = evlist__combined_sample_type(evlist);
callchain_param_setup(sample_type, perf_env__arch(perf_session__env(scr->session)));
e_machine = perf_session__e_machine(evsel__session(evsel), /*e_flags=*/NULL);
callchain_param_setup(sample_type, e_machine);
/* Enable fields for callchain entries */
if (symbol_conf.use_callchain &&
@ -3819,7 +3836,7 @@ static void script__setup_sample_type(struct perf_script *script)
struct perf_session *session = script->session;
u64 sample_type = evlist__combined_sample_type(session->evlist);
callchain_param_setup(sample_type, perf_env__arch(session->machines.host.env));
callchain_param_setup(sample_type, perf_session__e_machine(session, /*e_flags=*/NULL));
if (script->stitch_lbr && (callchain_param.record_mode != CALLCHAIN_LBR)) {
pr_warning("Can't find LBR callchain. Switch off --stitch-lbr.\n"
@ -4017,7 +4034,6 @@ int cmd_script(int argc, const char **argv)
.set = false,
.default_no_sample = true,
};
struct utsname uts;
char *script_path = NULL;
const char *dlfilter_file = NULL;
const char **__argv;
@ -4439,17 +4455,6 @@ script_found:
if (symbol__init(env) < 0)
goto out_delete;
uname(&uts);
if (data.is_pipe) { /* Assume pipe_mode indicates native_arch */
native_arch = true;
} else if (env->arch) {
if (!strcmp(uts.machine, env->arch))
native_arch = true;
else if (!strcmp(uts.machine, "x86_64") &&
!strcmp(env->arch, "i386"))
native_arch = true;
}
script.session = session;
script__setup_sample_type(&script);
@ -4484,6 +4489,7 @@ script_found:
if (generate_script_lang) {
struct stat perf_stat;
int input;
char *filename = strdup("perf-script");
if (output_set_by_user()) {
fprintf(stderr,
@ -4511,17 +4517,32 @@ script_found:
}
scripting_ops = script_spec__lookup(generate_script_lang);
if (!scripting_ops && ends_with(generate_script_lang, ".py")) {
scripting_ops = script_spec__lookup("python");
free(filename);
filename = strdup(generate_script_lang);
filename[strlen(filename) - 3] = '\0';
} else if (!scripting_ops && ends_with(generate_script_lang, ".pl")) {
scripting_ops = script_spec__lookup("perl");
free(filename);
filename = strdup(generate_script_lang);
filename[strlen(filename) - 3] = '\0';
}
if (!scripting_ops) {
fprintf(stderr, "invalid language specifier");
fprintf(stderr, "invalid language specifier '%s'\n", generate_script_lang);
err = -ENOENT;
goto out_delete;
}
if (!filename) {
err = -ENOMEM;
goto out_delete;
}
#ifdef HAVE_LIBTRACEEVENT
err = scripting_ops->generate_script(session->tevent.pevent,
"perf-script");
err = scripting_ops->generate_script(session->tevent.pevent, filename);
#else
err = scripting_ops->generate_script(NULL, "perf-script");
err = scripting_ops->generate_script(NULL, filename);
#endif
free(filename);
goto out_delete;
}

View file

@ -369,19 +369,11 @@ static int read_counter_cpu(struct evsel *counter, int cpu_map_idx)
static int read_counters_with_affinity(void)
{
struct evlist_cpu_iterator evlist_cpu_itr;
struct affinity saved_affinity, *affinity;
if (all_counters_use_bpf)
return 0;
if (!target__has_cpu(&target) || target__has_per_thread(&target))
affinity = NULL;
else if (affinity__setup(&saved_affinity) < 0)
return -1;
else
affinity = &saved_affinity;
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
struct evsel *counter = evlist_cpu_itr.evsel;
if (evsel__is_bpf(counter))
@ -393,8 +385,6 @@ static int read_counters_with_affinity(void)
if (!counter->err)
counter->err = read_counter_cpu(counter, evlist_cpu_itr.cpu_map_idx);
}
if (affinity)
affinity__cleanup(&saved_affinity);
return 0;
}
@ -793,7 +783,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
const bool forks = (argc > 0);
bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false;
struct evlist_cpu_iterator evlist_cpu_itr;
struct affinity saved_affinity, *affinity = NULL;
int err, open_err = 0;
bool second_pass = false, has_supported_counters;
@ -805,14 +794,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
child_pid = evsel_list->workload.pid;
}
if (!cpu_map__is_dummy(evsel_list->core.user_requested_cpus)) {
if (affinity__setup(&saved_affinity) < 0) {
err = -1;
goto err_out;
}
affinity = &saved_affinity;
}
evlist__for_each_entry(evsel_list, counter) {
counter->reset_group = false;
if (bpf_counter__load(counter, &target)) {
@ -825,49 +806,48 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
evlist__reset_aggr_stats(evsel_list);
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
counter = evlist_cpu_itr.evsel;
/*
* bperf calls evsel__open_per_cpu() in bperf__load(), so
* no need to call it again here.
*/
if (!target.use_bpf) {
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
counter = evlist_cpu_itr.evsel;
/*
* bperf calls evsel__open_per_cpu() in bperf__load(), so
* no need to call it again here.
*/
if (target.use_bpf)
break;
if (counter->reset_group || !counter->supported)
continue;
if (evsel__is_bperf(counter))
continue;
if (counter->reset_group || !counter->supported)
continue;
if (evsel__is_bperf(counter))
continue;
while (true) {
if (create_perf_stat_counter(counter, &stat_config,
evlist_cpu_itr.cpu_map_idx) == 0)
break;
while (true) {
if (create_perf_stat_counter(counter, &stat_config,
evlist_cpu_itr.cpu_map_idx) == 0)
break;
open_err = errno;
/*
* Weak group failed. We cannot just undo this
* here because earlier CPUs might be in group
* mode, and the kernel doesn't support mixing
* group and non group reads. Defer it to later.
* Don't close here because we're in the wrong
* affinity.
*/
if ((open_err == EINVAL || open_err == EBADF) &&
evsel__leader(counter) != counter &&
counter->weak_group) {
evlist__reset_weak_group(evsel_list, counter, false);
assert(counter->reset_group);
counter->supported = true;
second_pass = true;
break;
}
open_err = errno;
/*
* Weak group failed. We cannot just undo this here
* because earlier CPUs might be in group mode, and the kernel
* doesn't support mixing group and non group reads. Defer
* it to later.
* Don't close here because we're in the wrong affinity.
*/
if ((open_err == EINVAL || open_err == EBADF) &&
evsel__leader(counter) != counter &&
counter->weak_group) {
evlist__reset_weak_group(evsel_list, counter, false);
assert(counter->reset_group);
counter->supported = true;
second_pass = true;
break;
if (stat_handle_error(counter, open_err) != COUNTER_RETRY)
break;
}
if (stat_handle_error(counter, open_err) != COUNTER_RETRY)
break;
}
}
if (second_pass) {
/*
* Now redo all the weak group after closing them,
@ -875,7 +855,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
*/
/* First close errored or weak retry */
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
counter = evlist_cpu_itr.evsel;
if (!counter->reset_group && counter->supported)
@ -884,7 +864,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
perf_evsel__close_cpu(&counter->core, evlist_cpu_itr.cpu_map_idx);
}
/* Now reopen weak */
evlist__for_each_cpu(evlist_cpu_itr, evsel_list, affinity) {
evlist__for_each_cpu(evlist_cpu_itr, evsel_list) {
counter = evlist_cpu_itr.evsel;
if (!counter->reset_group)
@ -893,17 +873,18 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
while (true) {
pr_debug2("reopening weak %s\n", evsel__name(counter));
if (create_perf_stat_counter(counter, &stat_config,
evlist_cpu_itr.cpu_map_idx) == 0)
evlist_cpu_itr.cpu_map_idx) == 0) {
evlist_cpu_iterator__exit(&evlist_cpu_itr);
break;
}
open_err = errno;
if (stat_handle_error(counter, open_err) != COUNTER_RETRY)
if (stat_handle_error(counter, open_err) != COUNTER_RETRY) {
evlist_cpu_iterator__exit(&evlist_cpu_itr);
break;
}
}
}
}
affinity__cleanup(affinity);
affinity = NULL;
has_supported_counters = false;
evlist__for_each_entry(evsel_list, counter) {
@ -937,9 +918,8 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
}
if (evlist__apply_filters(evsel_list, &counter, &target)) {
pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n",
counter->filter, evsel__name(counter), errno,
str_error_r(errno, msg, sizeof(msg)));
pr_err("failed to set filter \"%s\" on event %s: %m\n",
counter->filter, evsel__name(counter));
return -1;
}
@ -1001,8 +981,8 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
}
if (workload_exec_errno) {
const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
pr_err("Workload failed: %s\n", emsg);
errno = workload_exec_errno;
pr_err("Workload failed: %m\n");
err = -1;
goto err_out;
}
@ -1066,7 +1046,6 @@ err_out:
if (forks)
evlist__cancel_workload(evsel_list);
affinity__cleanup(affinity);
return err;
}
@ -2447,6 +2426,7 @@ static int parse_tpebs_mode(const struct option *opt, const char *str,
int cmd_stat(int argc, const char **argv)
{
struct opt_aggr_mode opt_mode = {};
bool affinity = true, affinity_set = false;
struct option stat_options[] = {
OPT_BOOLEAN('T', "transaction", &transaction_run,
"hardware transaction statistics"),
@ -2575,6 +2555,8 @@ int cmd_stat(int argc, const char **argv)
"don't print 'summary' for CSV summary output"),
OPT_BOOLEAN(0, "quiet", &quiet,
"don't print any output, messages or warnings (useful with record)"),
OPT_BOOLEAN_SET(0, "affinity", &affinity, &affinity_set,
"enable (default) or disable affinity optimizations to reduce IPIs"),
OPT_CALLBACK(0, "cputype", &evsel_list, "hybrid cpu type",
"Only enable events on applying cpu with this type "
"for hybrid platform (e.g. core or atom)",
@ -2632,6 +2614,9 @@ int cmd_stat(int argc, const char **argv)
} else
stat_config.csv_sep = DEFAULT_SEPARATOR;
if (affinity_set)
evsel_list->no_affinity = !affinity;
if (argc && strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
argc = __cmd_record(stat_options, &opt_mode, argc, argv);
if (argc < 0)

View file

@ -2616,12 +2616,10 @@ static struct syscall *trace__syscall_info(struct trace *trace, struct evsel *ev
err = syscall__read_info(sc, trace);
if (err && verbose > 0) {
char sbuf[STRERR_BUFSIZE];
fprintf(trace->output, "Problems reading syscall %d: %d (%s)", id, -err,
str_error_r(-err, sbuf, sizeof(sbuf)));
errno = -err;
fprintf(trace->output, "Problems reading syscall %d: %m", id);
if (sc && sc->name)
fprintf(trace->output, "(%s)", sc->name);
fprintf(trace->output, " (%s)", sc->name);
fputs(" information\n", trace->output);
}
return err ? NULL : sc;
@ -2791,7 +2789,7 @@ static int trace__sys_enter(struct trace *trace, struct evsel *evsel,
struct thread_trace *ttrace;
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
e_machine = thread__e_machine(thread, trace->host);
e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
sc = trace__syscall_info(trace, evsel, e_machine, id);
if (sc == NULL)
goto out_put;
@ -2870,7 +2868,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel,
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
e_machine = thread__e_machine(thread, trace->host);
e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
sc = trace__syscall_info(trace, evsel, e_machine, id);
if (sc == NULL)
goto out_put;
@ -2936,7 +2934,7 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
struct thread_trace *ttrace;
thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
e_machine = thread__e_machine(thread, trace->host);
e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
sc = trace__syscall_info(trace, evsel, e_machine, id);
if (sc == NULL)
goto out_put;
@ -3287,7 +3285,9 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel,
if (evsel == trace->syscalls.events.bpf_output) {
int id = perf_evsel__sc_tp_uint(evsel, id, sample);
int e_machine = thread ? thread__e_machine(thread, trace->host) : EM_HOST;
int e_machine = thread
? thread__e_machine(thread, trace->host, /*e_flags=*/NULL)
: EM_HOST;
struct syscall *sc = trace__syscall_info(trace, evsel, e_machine, id);
if (sc) {
@ -4673,9 +4673,8 @@ out_error:
out_error_apply_filters:
fprintf(trace->output,
"Failed to set filter \"%s\" on event %s with %d (%s)\n",
evsel->filter, evsel__name(evsel), errno,
str_error_r(errno, errbuf, sizeof(errbuf)));
"Failed to set filter \"%s\" on event %s: %m\n",
evsel->filter, evsel__name(evsel));
goto out_delete_evlist;
}
out_error_mem:
@ -4683,7 +4682,7 @@ out_error_mem:
goto out_delete_evlist;
out_errno:
fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
fprintf(trace->output, "%m\n");
goto out_delete_evlist;
}
@ -4919,7 +4918,7 @@ static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trac
{
size_t printed = 0;
struct thread_trace *ttrace = thread__priv(thread);
int e_machine = thread__e_machine(thread, trace->host);
int e_machine = thread__e_machine(thread, trace->host, /*e_flags=*/NULL);
double ratio;
if (ttrace == NULL)
@ -5173,8 +5172,8 @@ static int trace__parse_events_option(const struct option *opt, const char *str,
int unset __maybe_unused)
{
struct trace *trace = (struct trace *)opt->value;
const char *s = str;
char *sep = NULL, *lists[2] = { NULL, NULL, };
const char *s;
char *strd, *sep = NULL, *lists[2] = { NULL, NULL, };
int len = strlen(str) + 1, err = -1, list, idx;
char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
char group_name[PATH_MAX];
@ -5183,13 +5182,17 @@ static int trace__parse_events_option(const struct option *opt, const char *str,
if (strace_groups_dir == NULL)
return -1;
s = strd = strdup(str);
if (strd == NULL)
return -1;
if (*s == '!') {
++s;
trace->not_ev_qualifier = true;
}
while (1) {
if ((sep = strchr(s, ',')) != NULL)
if ((sep = strchr((char *)s, ',')) != NULL)
*sep = '\0';
list = 0;
@ -5257,8 +5260,7 @@ out:
free(strace_groups_dir);
free(lists[0]);
free(lists[1]);
if (sep)
*sep = ',';
free(strd);
return err;
}

View file

@ -54,7 +54,6 @@ declare -a FILES=(
"arch/s390/include/uapi/asm/kvm.h"
"arch/s390/include/uapi/asm/sie.h"
"arch/arm64/include/uapi/asm/kvm.h"
"arch/arm64/include/uapi/asm/unistd.h"
"arch/alpha/include/uapi/asm/errno.h"
"arch/mips/include/asm/errno.h"
"arch/mips/include/uapi/asm/errno.h"

View file

@ -1,36 +0,0 @@
#
# List of known perf commands.
# command name category [deprecated] [common]
#
perf-annotate mainporcelain common
perf-archive mainporcelain common
perf-bench mainporcelain common
perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common
perf-data mainporcelain common
perf-diff mainporcelain common
perf-c2c mainporcelain common
perf-config mainporcelain common
perf-evlist mainporcelain common
perf-ftrace mainporcelain common
perf-inject mainporcelain common
perf-iostat mainporcelain common
perf-kallsyms mainporcelain common
perf-kmem mainporcelain traceevent
perf-kvm mainporcelain common
perf-kwork mainporcelain traceevent
perf-list mainporcelain common
perf-lock mainporcelain traceevent
perf-mem mainporcelain common
perf-probe mainporcelain full
perf-record mainporcelain common
perf-report mainporcelain common
perf-sched mainporcelain traceevent
perf-script mainporcelain common
perf-stat mainporcelain common
perf-test mainporcelain common
perf-timechart mainporcelain traceevent
perf-top mainporcelain common
perf-trace mainporcelain audit
perf-version mainporcelain common
perf-daemon mainporcelain common

View file

@ -142,7 +142,7 @@ copy_class_filename(const char * class_sign, const char * file_name, char * resu
*/
if (*class_sign == 'L') {
size_t j, i = 0;
char *p = strrchr(class_sign, '/');
const char *p = strrchr(class_sign, '/');
if (p) {
/* drop the 'L' prefix and copy up to the final '/' */
for (i = 0; i < (size_t)(p - class_sign); i++)

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