perf tools changes for v7.4

- Support instruction tracking on arm64 for data type profiling, resolving
   stack, global, per-CPU and 'current' variable accesses, so that 'perf
   annotate --data-type' resolves types on arm64 the way it does on x86.
 
 - Port the Python scripts to the perf module and standalone execution, and
   improve the module: lazy sample callchains and event copies, GIL
   handling, better session/thread lookup, new treport, flamegraph and
   sqlite/postgres exporters.
 
 - Reenable and fix the attribute expectation test suite: per-PMU bit
   masks, other core PMUs' events, dummy tracking events, group checks
   and spelled out skip reasons.
 
 - perf trace: filter the target's tasks in BPF, open the BPF output event
   on every CPU, add an option to disable syscall augmentation and raise
   TRACE_AUG_MAX_BUF.
 
 - perf jitdump: harden record parsing, validating unwinding sizes and
   symbol names, byte-swapping debug entries via safe accessors and fixing
   frees on error paths.
 
 - perf annotate-data fixes: bound the member nesting recursion, resolve
   type DIEs in the debug file they came from, adjust the offset for
   flex-arrays and show the sample count in the data-type browser.
 
 - perf symbol and debug info: try linked debug files for DSOs, avoid
   repeated failing searches, set binary/symtab types for split kallsyms,
   JIT maps and the build-id cache, fix libbfd symbol loading.
 
 - perf config: serialize config file access with a mutex, add the
   DEFINE_MUTEX() and DO_ONCE() primitives and a robust process shared
   mutex, add the core.hybrid-merge option.
 
 - perf report: add --progress and --no-progress options.
 
 - perf mem: add a false sharing workload to 'perf test', request
   PERF_SAMPLE_CPU by default, use the IBS swfilt filter when available
   and decode L0 in the memory level.
 
 - perf test: take turns using the perf mlock budget in the mmaping tests,
   add the 'needs_mlock' suite flag, scope the probe based tests to their
   PID and make more tests non-exclusive.
 
 - perf vendor events intel: update events and metrics to TMA 5.2, refresh
   the event tables and fix umask encodings.
 
 - perf build: run shellcheck, mypy and pylint in parallel, make pylint
   opt-out with NO_PYLINT=1, fix clean and install dependencies.
 
 - Add a script and a 'make sync-headers' target to sync the tools/ copies
   of kernel headers with the kernel sources, plus the resulting syncs of
   the cpufeatures, KVM, fs, mount, fcntl, socket, rtnetlink, if_addr and
   sound headers.
 
 - Fix cs-etm HW_ID mapping synthesis for raw trace, queue teardown leaks
   and duplicate v0 global mappings.
 
 - Add a 'perf bench atomic' benchmark for atomic operations.
 
 - Filter events before creating lock_stat in 'perf lock contention'.
 
 - Add a 'perf test' case for events re-armed with PERF_EVENT_IOC_REFRESH.
 
 - Fix memory leaks on 'perf c2c' output fields and add function view
   stdio coverage to its test.
 
 - Fix a NULL dereference resolving callchains in 'perf machine'.
 
 - Optimize the libdw fallback when DWARF is missing and try the symbol
   file first when checking for debuginfo.
 
 - Don't call eprintf() in pr_debugN() when not verbose.
 
 - Don't delete cumulative caller entries before the stat_acc decays in
   'perf report'.
 
 - Fix ring buffer cursor handling: keep the consumed cursor in forward
   mode and use the head selected by read_init.
 
 - Fix 'perf test mmap-basic' user rdpmc detection and only test userspace
   reading on supported platforms.
 
 - Build fixes: include sys/types.h for ssize_t, errno.h before kernel
   headers and fix jevents.py type annotations for mypy 2.x.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCauUL4QAKCRCyPKLppCJ+
 JzsyAQCNjqGOBYEUaDbQAbK1/1h9D9QER9s+4aU3Np2zT9XSPAD/RkY12uxT3YAO
 NcQlaj0On+I46SkgyGzGrV9mOvDZJwo=
 =b9um
 -----END PGP SIGNATURE-----

Merge tag 'perf-tools-for-v7.4-1-2026-10-30' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next

Pull perf tool updates from Arnaldo Carvalho de Melo:

 - Support instruction tracking on arm64 for data type profiling,
   resolving stack, global, per-CPU and 'current' variable accesses, so
   that 'perf annotate --data-type' resolves types on arm64 the way it
   does on x86.

 - Port the Python scripts to the perf module and standalone execution,
   and improve the module: lazy sample callchains and event copies, GIL
   handling, better session/thread lookup, new treport, flamegraph and
   sqlite/postgres exporters.

 - Reenable and fix the attribute expectation test suite: per-PMU bit
   masks, other core PMUs' events, dummy tracking events, group checks
   and spelled out skip reasons.

 - perf trace: filter the target's tasks in BPF, open the BPF output
   event on every CPU, add an option to disable syscall augmentation and
   raise TRACE_AUG_MAX_BUF.

 - perf jitdump: harden record parsing, validating unwinding sizes and
   symbol names, byte-swapping debug entries via safe accessors and
   fixing frees on error paths.

 - perf annotate-data fixes: bound the member nesting recursion, resolve
   type DIEs in the debug file they came from, adjust the offset for
   flex-arrays and show the sample count in the data-type browser.

 - perf symbol and debug info: try linked debug files for DSOs, avoid
   repeated failing searches, set binary/symtab types for split
   kallsyms, JIT maps and the build-id cache, fix libbfd symbol loading.

 - perf config: serialize config file access with a mutex, add the
   DEFINE_MUTEX() and DO_ONCE() primitives and a robust process shared
   mutex, add the core.hybrid-merge option.

 - perf report: add --progress and --no-progress options.

 - perf mem: add a false sharing workload to 'perf test', request
   PERF_SAMPLE_CPU by default, use the IBS swfilt filter when available
   and decode L0 in the memory level.

 - perf test: take turns using the perf mlock budget in the mmaping
   tests, add the 'needs_mlock' suite flag, scope the probe based tests
   to their PID and make more tests non-exclusive.

 - perf vendor events intel: update events and metrics to TMA 5.2,
   refresh the event tables and fix umask encodings.

 - perf build: run shellcheck, mypy and pylint in parallel, make pylint
   opt-out with NO_PYLINT=1, fix clean and install dependencies.

 - Add a script and a 'make sync-headers' target to sync the tools/
   copies of kernel headers with the kernel sources, plus the resulting
   syncs of the cpufeatures, KVM, fs, mount, fcntl, socket, rtnetlink,
   if_addr and sound headers.

 - Fix cs-etm HW_ID mapping synthesis for raw trace, queue teardown
   leaks and duplicate v0 global mappings.

 - Add a 'perf bench atomic' benchmark for atomic operations.

 - Filter events before creating lock_stat in 'perf lock contention'.

 - Add a 'perf test' case for events re-armed with
   PERF_EVENT_IOC_REFRESH.

 - Fix memory leaks on 'perf c2c' output fields and add function view
   stdio coverage to its test.

 - Fix a NULL dereference resolving callchains in 'perf machine'.

 - Optimize the libdw fallback when DWARF is missing and try the symbol
   file first when checking for debuginfo.

 - Don't call eprintf() in pr_debugN() when not verbose.

 - Don't delete cumulative caller entries before the stat_acc decays in
   'perf report'.

 - Fix ring buffer cursor handling: keep the consumed cursor in forward
   mode and use the head selected by read_init.

 - Fix 'perf test mmap-basic' user rdpmc detection and only test
   userspace reading on supported platforms.

 - Build fixes: include sys/types.h for ssize_t, errno.h before kernel
   headers and fix jevents.py type annotations for mypy 2.x.

* tag 'perf-tools-for-v7.4-1-2026-10-30' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next: (425 commits)
  perf machine: Fix NULL deref in thread__resolve_callchain_sample()
  perf pmu-events: Fix jevents.py type annotations for mypy 2.x
  perf parse-events: Include errno.h before kernel headers
  perf print_insn: Include sys/types.h for ssize_t
  perf tests mmap-basic: Fix user rdpmc detection logic
  perf tests mmap-basic: Only test userspace reading on supported platforms
  perf mmap: Preserve the consumed cursor in forward mode
  perf mmap: Use the head selected by read_init
  perf hist: Do not delete cumulative caller entries before stat_acc decays
  perf debug: Avoid calling eprintf() in pr_debugN() when verbose < n
  perf libdw: Optimize fallback logic for missing DWARF
  tools headers: Sync KVM headers with the kernel sources
  tools headers: Sync UAPI sound/asound.h with the kernel sources
  tools headers: Sync UAPI linux/mount.h with the kernel sources
  tools headers: Sync UAPI linux/fs.h with the kernel sources
  tools headers: Sync UAPI linux/fcntl.h with the kernel sources
  tools headers: Sync linux/socket.h with the kernel sources
  tools arch x86: Sync the cpufeatures.h copy with the kernel sources
  tools headers UAPI: Sync linux/rtnetlink.h with the kernel sources
  tools headers UAPI: Sync linux/if_addr.h with the kernel sources
  ...
This commit is contained in:
Linus Torvalds 2026-10-30 21:54:38 -07:00
commit dd384658c7
650 changed files with 43377 additions and 25530 deletions

View File

@ -21907,7 +21907,7 @@ F: tools/lib/perf/
F: tools/perf/
PERFORMANCE EVENTS TOOLING ARM64
R: John Garry <john.g.garry@oracle.com>
R: John Garry <john.garry@linux.dev>
R: Will Deacon <will@kernel.org>
R: James Clark <james.clark@linaro.org>
R: Mike Leach <mike.leach@arm.com>

View File

@ -111,6 +111,7 @@ struct kvm_regs {
#define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */
#define KVM_ARM_VCPU_HAS_EL2 7 /* Support nested virtualization */
#define KVM_ARM_VCPU_HAS_EL2_E2H0 8 /* Limit NV support to E2H RES0 */
#define KVM_ARM_VCPU_PMU_V3_STRICT 9 /* No default PMU creation */
struct kvm_vcpu_init {
__u32 target;

View File

@ -437,6 +437,24 @@ struct kvm_ppc_cpu_char {
__u64 behaviour_mask; /* valid bits in behaviour */
};
/* For KVM_PPC_GET_COMPAT_CAPS */
struct kvm_ppc_compat_caps {
__u64 size; /* Size of this structure */
__u64 flags; /* Reserved for future use */
__u64 compat_capabilities; /* Capabilities supported by the host */
};
#define KVM_PPC_COMPAT_CAPS_SIZE_VER0 24 /* sizeof first published struct */
/*
* Capability bits for compat_capabilities field in kvm_ppc_compat_caps.
* These bits indicate which processor compatibility modes are supported.
*/
#define KVM_PPC_COMPAT_CAP_POWER9 (1ULL << 62)
#define KVM_PPC_COMPAT_CAP_POWER10 (1ULL << 61)
#define KVM_PPC_COMPAT_CAP_POWER11 (1ULL << 60)
#define KVM_PPC_COMPAT_BITMASK (KVM_PPC_COMPAT_CAP_POWER9 | \
KVM_PPC_COMPAT_CAP_POWER10 | \
KVM_PPC_COMPAT_CAP_POWER11)
/*
* Values for character and character_mask.
* These are identical to the values used by H_GET_CPU_CHARACTERISTICS.

View File

@ -136,8 +136,12 @@
#define X86_FEATURE_HYPERVISOR ( 4*32+31) /* "hypervisor" Running on a hypervisor */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
#define X86_FEATURE_SM2 ( 5*32+ 0) /* "sm2" SM2 algorithm */
#define X86_FEATURE_SM2_EN ( 5*32+ 1) /* "sm2_en" SM2 enabled */
#define X86_FEATURE_XSTORE ( 5*32+ 2) /* "rng" RNG present (xstore) */
#define X86_FEATURE_XSTORE_EN ( 5*32+ 3) /* "rng_en" RNG enabled */
#define X86_FEATURE_CCS ( 5*32+ 4) /* "ccs" SM3 + SM4 instructions */
#define X86_FEATURE_CCS_EN ( 5*32+ 5) /* "ccs_en" CCS enabled */
#define X86_FEATURE_XCRYPT ( 5*32+ 6) /* "ace" on-CPU crypto (xcrypt) */
#define X86_FEATURE_XCRYPT_EN ( 5*32+ 7) /* "ace_en" on-CPU crypto enabled */
#define X86_FEATURE_ACE2 ( 5*32+ 8) /* "ace2" Advanced Cryptography Engine v2 */
@ -146,6 +150,12 @@
#define X86_FEATURE_PHE_EN ( 5*32+11) /* "phe_en" PHE enabled */
#define X86_FEATURE_PMM ( 5*32+12) /* "pmm" PadLock Montgomery Multiplier */
#define X86_FEATURE_PMM_EN ( 5*32+13) /* "pmm_en" PMM enabled */
#define X86_FEATURE_RNG2 ( 5*32+22) /* "rng2" RNG v2 */
#define X86_FEATURE_RNG2_EN ( 5*32+23) /* "rng2_en" RNG2 enabled */
#define X86_FEATURE_PHE2 ( 5*32+25) /* "phe2" PadLock Hash Engine v2 */
#define X86_FEATURE_PHE2_EN ( 5*32+26) /* "phe2_en" PHE2 enabled */
#define X86_FEATURE_RSA ( 5*32+27) /* "rsa" Big-number arithmetic */
#define X86_FEATURE_RSA_EN ( 5*32+28) /* "rsa_en" RSA enabled */
/* More extended AMD flags: CPUID level 0x80000001, ECX, word 6 */
#define X86_FEATURE_LAHF_LM ( 6*32+ 0) /* "lahf_lm" LAHF/SAHF in long mode */
@ -365,6 +375,8 @@
#define X86_FEATURE_HWP_HIGHEST_PERF_CHANGE (14*32+15) /* HWP Highest perf change */
#define X86_FEATURE_HFI (14*32+19) /* "hfi" Hardware Feedback Interface */
#define X86_FEATURE_DPTI (14*32+24) /* Intel Directed Package Thermal Interrupt */
/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */
#define X86_FEATURE_NPT (15*32+ 0) /* "npt" Nested Page Table support */
#define X86_FEATURE_LBRV (15*32+ 1) /* "lbrv" LBR Virtualization support */
@ -465,6 +477,8 @@
#define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* No Nested Data Breakpoints */
#define X86_FEATURE_WRMSR_XX_BASE_NS (20*32+ 1) /* WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing */
#define X86_FEATURE_LFENCE_RDTSC (20*32+ 2) /* LFENCE always serializing / synchronizes RDTSC */
#define X86_FEATURE_TLBSYNC_SFW_NO (20*32+ 4) /* TLBI Erratum #1718 fixed in microcode */
#define X86_FEATURE_VERW_CLEAR (20*32+ 5) /* The memory form of VERW mitigates TSA */
#define X86_FEATURE_NULL_SEL_CLR_BASE (20*32+ 6) /* Null Selector Clears Base */
@ -575,4 +589,5 @@
#define X86_BUG_TSA X86_BUG( 1*32+ 9) /* "tsa" CPU is affected by Transient Scheduler Attacks */
#define X86_BUG_VMSCAPE X86_BUG( 1*32+10) /* "vmscape" CPU is affected by VMSCAPE attacks from guests */
#define X86_BUG_SEAMRET_INVD_VMCS X86_BUG( 1*32+11) /* "seamret_invd_vmcs" SEAMRET from P-SEAMLDR clears the current VMCS */
#define X86_BUG_TLBI X86_BUG( 1*32+12) /* "tlbi" AMD TLBI Erratum #1718 */
#endif /* _ASM_X86_CPUFEATURES_H */

View File

@ -350,6 +350,13 @@
#define ARCH_PEBS_LBR_SHIFT 40
#define ARCH_PEBS_LBR (0x3ull << ARCH_PEBS_LBR_SHIFT)
#define ARCH_PEBS_VECR_XMM BIT_ULL(49)
#define ARCH_PEBS_VECR_YMMH BIT_ULL(50)
#define ARCH_PEBS_VECR_EGPRS BIT_ULL(51)
#define ARCH_PEBS_VECR_OPMASK BIT_ULL(53)
#define ARCH_PEBS_VECR_ZMMH BIT_ULL(54)
#define ARCH_PEBS_VECR_H16ZMM BIT_ULL(55)
#define ARCH_PEBS_VECR_EXT_SHIFT 49
#define ARCH_PEBS_VECR_EXT (0x7full << ARCH_PEBS_VECR_EXT_SHIFT)
#define ARCH_PEBS_GPR BIT_ULL(61)
#define ARCH_PEBS_AUX BIT_ULL(62)
#define ARCH_PEBS_EN BIT_ULL(63)

View File

@ -2,6 +2,8 @@
#ifndef _ASM_X86_PERF_REGS_H
#define _ASM_X86_PERF_REGS_H
#include <linux/bits.h>
enum perf_event_x86_regs {
PERF_REG_X86_AX,
PERF_REG_X86_BX,
@ -27,9 +29,35 @@ enum perf_event_x86_regs {
PERF_REG_X86_R13,
PERF_REG_X86_R14,
PERF_REG_X86_R15,
/*
* The eGPRs/SSP and XMM have overlaps. Only one can be used
* at a time. The ABI PERF_SAMPLE_REGS_ABI_SIMD is used to
* distinguish which one is used. If PERF_SAMPLE_REGS_ABI_SIMD
* is set, then eGPRs/SSP is used, otherwise, XMM is used.
*
* Extended GPRs (eGPRs)
*/
PERF_REG_X86_R16,
PERF_REG_X86_R17,
PERF_REG_X86_R18,
PERF_REG_X86_R19,
PERF_REG_X86_R20,
PERF_REG_X86_R21,
PERF_REG_X86_R22,
PERF_REG_X86_R23,
PERF_REG_X86_R24,
PERF_REG_X86_R25,
PERF_REG_X86_R26,
PERF_REG_X86_R27,
PERF_REG_X86_R28,
PERF_REG_X86_R29,
PERF_REG_X86_R30,
PERF_REG_X86_R31,
PERF_REG_X86_SSP,
/* These are the limits for the GPRs. */
PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1,
PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1,
PERF_REG_MISC_MAX = PERF_REG_X86_SSP + 1,
/* These all need two bits set because they are 128bit */
PERF_REG_X86_XMM0 = 32,
@ -54,5 +82,30 @@ enum perf_event_x86_regs {
};
#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
#define PERF_X86_EGPRS_MASK __GENMASK_ULL(PERF_REG_X86_R31, PERF_REG_X86_R16)
enum {
PERF_X86_SIMD_XMM_REGS = 16,
PERF_X86_SIMD_YMM_REGS = 16,
PERF_X86_SIMD_ZMM_REGS = 32,
PERF_X86_SIMD_VEC_REGS_MAX = PERF_X86_SIMD_ZMM_REGS,
PERF_X86_SIMD_OPMASK_REGS = 8,
PERF_X86_SIMD_PRED_REGS_MAX = PERF_X86_SIMD_OPMASK_REGS,
};
#define PERF_X86_SIMD_PRED_MASK __GENMASK(PERF_X86_SIMD_PRED_REGS_MAX - 1, 0)
#define PERF_X86_SIMD_VEC_MASK __GENMASK_ULL(PERF_X86_SIMD_VEC_REGS_MAX - 1, 0)
#define PERF_X86_H16ZMM_BASE 16
enum {
/* 1 qword = 8 bytes */
PERF_X86_OPMASK_QWORDS = 1,
PERF_X86_XMM_QWORDS = 2,
PERF_X86_YMM_QWORDS = 4,
PERF_X86_ZMM_QWORDS = 8,
PERF_X86_SIMD_QWORDS_MAX = PERF_X86_ZMM_QWORDS,
};
#endif /* _ASM_X86_PERF_REGS_H */

View File

@ -79,12 +79,13 @@ FEATURE_TESTS_BASIC := \
libelf-zstd \
libnuma \
numa_num_possible_cpus \
libpython \
python-module \
libslang \
libtraceevent \
libcpupower \
pthread-attr-setaffinity-np \
pthread-barrier \
pthread-mutex-robust \
reallocarray \
stackprotector-all \
timerfd \
@ -113,8 +114,7 @@ FEATURE_TESTS_EXTRA := \
compile-x32 \
cplus-demangle \
cxa-demangle \
gtk2 \
gtk2-infobar \
gtk4 \
hello \
babeltrace2-ctf-writer \
libcapstone \
@ -122,7 +122,6 @@ FEATURE_TESTS_EXTRA := \
libbfd-liberty \
libbfd-liberty-z \
libopencsd \
libperl \
llvm \
libbpf \
libpfm4 \
@ -146,7 +145,7 @@ FEATURE_DISPLAY ?= \
libelf \
libnuma \
numa_num_possible_cpus \
libpython \
python-module \
libcapstone \
llvm-perf \
zlib \

View File

@ -11,8 +11,7 @@ FILES= \
test-eventfd.bin \
test-fortify-source.bin \
test-glibc.bin \
test-gtk2.bin \
test-gtk2-infobar.bin \
test-gtk4.bin \
test-hello.bin \
test-libbfd.bin \
test-libbfd-threadsafe.bin \
@ -32,8 +31,7 @@ FILES= \
test-libdebuginfod.bin \
test-libnuma.bin \
test-numa_num_possible_cpus.bin \
test-libperl.bin \
test-libpython.bin \
test-python-module.bin \
test-libslang.bin \
test-libtraceevent.bin \
test-libcpupower.bin \
@ -43,6 +41,7 @@ FILES= \
$(foreach arch,$(LIBUNWIND_ARCHS),test-libunwind-$(arch).bin test-libunwind-debug-frame-$(arch).bin) \
test-pthread-attr-setaffinity-np.bin \
test-pthread-barrier.bin \
test-pthread-mutex-robust.bin \
test-stackprotector-all.bin \
test-timerfd.bin \
test-babeltrace2-ctf-writer.bin \
@ -130,6 +129,9 @@ $(OUTPUT)test-pthread-attr-setaffinity-np.bin:
$(OUTPUT)test-pthread-barrier.bin:
$(BUILD) -lpthread
$(OUTPUT)test-pthread-mutex-robust.bin:
$(BUILD) -lpthread
$(OUTPUT)test-stackprotector-all.bin:
$(BUILD) -fstack-protector-all
@ -240,46 +242,24 @@ $(OUTPUT)test-libcpupower.bin:
$(OUTPUT)test-libtracefs.bin:
$(BUILD) $(shell $(PKG_CONFIG) --cflags libtracefs 2>/dev/null) -ltracefs
$(OUTPUT)test-gtk2.bin:
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) -Wno-deprecated-declarations
$(OUTPUT)test-gtk4.bin:
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk4 2>/dev/null)
$(OUTPUT)test-gtk2-infobar.bin:
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
ifeq ($(CC_NO_CLANG), 0)
PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS := $(filter-out -flto=auto -ffat-lto-objects, $(PERL_EMBED_CCOPTS))
PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS))
FLAGS_PERL_EMBED += -Wno-compound-token-split-by-macro
endif
$(OUTPUT)test-libperl.bin:
$(BUILD) $(FLAGS_PERL_EMBED)
$(OUTPUT)test-libpython.bin:
$(OUTPUT)test-python-module.bin:
$(BUILD) $(FLAGS_PYTHON_EMBED)
$(OUTPUT)test-libbfd.bin:
$(BUILD_BFD)
$(BUILD_BFD) || $(BUILD_BFD) -lzstd
$(OUTPUT)test-libbfd-threadsafe.bin:
$(BUILD_BFD) || $(BUILD_BFD) -liberty || $(BUILD_BFD) -liberty -lz
$(BUILD_BFD) || $(BUILD_BFD) -lzstd || $(BUILD_BFD) -liberty || $(BUILD_BFD) -liberty -lz
$(OUTPUT)test-disassembler-four-args.bin:
$(BUILD_BFD) -lopcodes || $(BUILD_BFD) -lopcodes -liberty || \
$(BUILD_BFD) -lopcodes || $(BUILD_BFD) -lopcodes -lzstd || $(BUILD_BFD) -lopcodes -liberty || \
$(BUILD_BFD) -lopcodes -liberty -lz
$(OUTPUT)test-disassembler-init-styled.bin:
$(BUILD_BFD) -lopcodes || $(BUILD_BFD) -lopcodes -liberty || \
$(BUILD_BFD) -lopcodes || $(BUILD_BFD) -lopcodes -liberty || \
$(BUILD_BFD) -lopcodes -liberty -lz
$(OUTPUT)test-reallocarray.bin:

View File

@ -10,8 +10,8 @@
* Quirk: Python headers cannot be in arbitrary places, so keep this testcase at
* the top:
*/
#define main main_test_libpython
# include "test-libpython.c"
#define main main_test_python_module
# include "test-python-module.c"
#undef main
#define main main_test_hello
@ -90,6 +90,10 @@
# include "test-pthread-barrier.c"
#undef main
#define main main_test_pthread_mutex_robust
# include "test-pthread-mutex-robust.c"
#undef main
#define main main_test_scandirat
# include "test-scandirat.c"
#undef main
@ -148,7 +152,7 @@
int main(int argc, char *argv[])
{
main_test_libpython();
main_test_python_module();
main_test_hello();
main_test_libelf();
main_test_gettid();
@ -167,6 +171,7 @@ int main(int argc, char *argv[])
main_test_zlib();
main_test_pthread_attr_setaffinity_np();
main_test_pthread_barrier();
main_test_pthread_mutex_robust();
main_test_lzma();
main_test_bpf();
main_test_scandirat();

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
#undef _GNU_SOURCE
#define _GNU_SOURCE
#include <unistd.h>

View File

@ -1,12 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include <gtk/gtk.h>
#pragma GCC diagnostic error "-Wstrict-prototypes"
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
gtk_info_bar_new();
return 0;
}

View File

@ -3,9 +3,9 @@
#include <gtk/gtk.h>
#pragma GCC diagnostic error "-Wstrict-prototypes"
int main(int argc, char *argv[])
int main(void)
{
gtk_init(&argc, &argv);
gtk_init();
return 0;
}

View File

@ -49,8 +49,16 @@ int test_elfutils(void)
return 0;
}
/* Needs elfutils 0.160: taking its address fails the probe, not the link. */
int test_libdw_cu_getdwarf(void)
{
void *sym = (void *)dwarf_cu_getdwarf;
return sym == NULL;
}
int main(void)
{
return test_libdw() + test_libdw_unwind() + test_libdw_getlocations() +
test_libdw_getcfi() + test_elfutils();
test_libdw_getcfi() + test_libdw_cu_getdwarf() + test_elfutils();
}

View File

@ -1,10 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <EXTERN.h>
#include <perl.h>
int main(void)
{
perl_alloc();
return 0;
}

View File

@ -1,10 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <Python.h>
int main(void)
{
Py_Initialize();
return 0;
}
#undef _GNU_SOURCE

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
#include <pthread.h>
int main(void)
{
pthread_mutexattr_t attr;
pthread_mutex_t mtx;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
pthread_mutex_init(&mtx, &attr);
pthread_mutex_consistent(&mtx);
pthread_mutex_destroy(&mtx);
pthread_mutexattr_destroy(&attr);
return 0;
}

View File

@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
#include <Python.h>
int main(void)
{
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
.m_name = "test",
};
PyObject *module = PyModule_Create(&moduledef);
return module ? 0 : -1;
}

View File

@ -6,7 +6,7 @@
int main(void)
{
struct itimerspec new_value;
struct itimerspec new_value = {};
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (fd < 0)

View File

@ -2,6 +2,7 @@
#ifndef _TOOLS_DIS_ASM_COMPAT_H
#define _TOOLS_DIS_ASM_COMPAT_H
#include <stdarg.h>
#include <stdio.h>
#include <dis-asm.h>

View File

@ -36,6 +36,7 @@ enum {
IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
IFA_TARGET_NETNSID,
IFA_PROTO, /* u8, address protocol */
IFA_MC_USERS, /* u32, multicast group users */
__IFA_MAX,
};

View File

@ -997,6 +997,8 @@ struct kvm_enable_cap {
#define KVM_CAP_S390_KEYOP 247
#define KVM_CAP_S390_VSIE_ESAMODE 248
#define KVM_CAP_S390_HPAGE_2G 249
#define KVM_CAP_PPC_COMPAT_CAPS 250
#define KVM_CAP_ARM_PMU_V3_STRICT 251
struct kvm_irq_routing_irqchip {
__u32 irqchip;
@ -1341,6 +1343,8 @@ struct kvm_s390_keyop {
/* Available with KVM_CAP_COUNTER_OFFSET */
#define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO, 0xb5, struct kvm_arm_counter_offset)
#define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO, 0xb6, struct reg_mask_range)
/* Available with KVM_CAP_PPC_COMPAT_CAPS */
#define KVM_PPC_GET_COMPAT_CAPS _IO(KVMIO, 0xb8)
/* ioctl for vm fd */
#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)

View File

@ -314,8 +314,9 @@ enum {
*/
enum perf_sample_regs_abi {
PERF_SAMPLE_REGS_ABI_NONE = 0,
PERF_SAMPLE_REGS_ABI_32 = 1,
PERF_SAMPLE_REGS_ABI_64 = 2,
PERF_SAMPLE_REGS_ABI_32 = (1 << 0),
PERF_SAMPLE_REGS_ABI_64 = (1 << 1),
PERF_SAMPLE_REGS_ABI_SIMD = (1 << 2),
};
/*
@ -383,6 +384,7 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER7 128 /* Add: sig_data */
#define PERF_ATTR_SIZE_VER8 136 /* Add: config3 */
#define PERF_ATTR_SIZE_VER9 144 /* add: config4 */
#define PERF_ATTR_SIZE_VER10 176 /* Add: sample_simd_{vec|pred}_reg_* */
/*
* 'struct perf_event_attr' contains various attributes that define
@ -547,6 +549,29 @@ struct perf_event_attr {
__u64 config3; /* extension of config2 */
__u64 config4; /* extension of config3 */
/*
* Defines the sampling SIMD/PRED(predicate) registers bitmap and
* qwords (8 bytes) length.
*
* sample_simd_regs_enabled != 0 indicates there are SIMD/PRED
* registers to be sampled, the SIMD/PRED registers bitmap and
* qwords length are represented in
* sample_simd_{vec|pred}_reg_{intr|user} and
* sample_simd_{vec|pred}_reg_qwords fields separately.
*
* sample_simd_regs_enabled == 0 indicates no SIMD/PRED registers
* are sampled.
*/
__u16 sample_simd_regs_enabled;
__u16 sample_simd_pred_reg_qwords;
__u16 sample_simd_vec_reg_qwords;
__u16 __reserved_4;
__u32 sample_simd_pred_reg_intr;
__u32 sample_simd_pred_reg_user;
__u64 sample_simd_vec_reg_intr;
__u64 sample_simd_vec_reg_user;
};
/*
@ -1020,7 +1045,15 @@ enum perf_event_type {
* } && PERF_SAMPLE_BRANCH_STACK
*
* { u64 abi; # enum perf_sample_regs_abi
* u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
* u64 regs[weight(mask)];
* struct {
* u64 nr_vectors; # 0 ... weight(sample_simd_vec_reg_user)
* u64 vector_qwords; # 0 ... sample_simd_vec_reg_qwords
* u64 nr_pred; # 0 ... weight(sample_simd_pred_reg_user)
* u64 pred_qwords; # 0 ... sample_simd_pred_reg_qwords
* u64 data[nr_vectors * vector_qwords + nr_pred * pred_qwords];
* } && (abi & PERF_SAMPLE_REGS_ABI_SIMD)
* } && PERF_SAMPLE_REGS_USER
*
* { u64 size;
* char data[size];
@ -1047,7 +1080,15 @@ enum perf_event_type {
* { u64 data_src; } && PERF_SAMPLE_DATA_SRC
* { u64 transaction; } && PERF_SAMPLE_TRANSACTION
* { u64 abi; # enum perf_sample_regs_abi
* u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
* u64 regs[weight(mask)];
* struct {
* u64 nr_vectors; # 0 ... weight(sample_simd_vec_reg_intr)
* u64 vector_qwords; # 0 ... sample_simd_vec_reg_qwords
* u64 nr_pred; # 0 ... weight(sample_simd_pred_reg_intr)
* u64 pred_qwords; # 0 ... sample_simd_pred_reg_qwords
* u64 data[nr_vectors * vector_qwords + nr_pred * pred_qwords];
* } && (abi & PERF_SAMPLE_REGS_ABI_SIMD)
* } && PERF_SAMPLE_REGS_INTR
* { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR
* { u64 cgroup;} && PERF_SAMPLE_CGROUP
* { u64 data_page_size;} && PERF_SAMPLE_DATA_PAGE_SIZE

View File

@ -399,6 +399,7 @@ enum rtattr_type_t {
RTA_DPORT,
RTA_NH_ID,
RTA_FLOWLABEL,
RTA_DEL_REASON,
__RTA_MAX
};
@ -407,6 +408,30 @@ enum rtattr_type_t {
#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
/* RTA_DEL_REASON: why the kernel deleted the route. u32.
* Emitted only on RTM_DELROUTE notifications, and only when the deletion
* path records a cause. Absence means either an older kernel or a
* deletion path that does not (yet) record its cause - consumers must
* treat "absent" and "unspec" identically. New causes may be appended.
* Currently only IPv6 deletion paths record a cause.
*
* The attribute is notification-only: the kernel rejects it in
* requests, so a notification must not be echoed back verbatim.
*
* The value space is family-agnostic: a value must never be
* reinterpreted per address family. A cause that only one family can
* produce still gets its own value rather than reusing another
* family's.
*/
enum rt_del_reason {
RT_DEL_REASON_UNSPEC, /* cause not recorded */
RT_DEL_REASON_EXPIRED, /* RTF_EXPIRES lifetime ran out (GC) */
RT_DEL_REASON_RA_WITHDRAWN, /* zero-lifetime RA / PIO / RIO */
__RT_DEL_REASON_MAX
};
#define RT_DEL_REASON_MAX (__RT_DEL_REASON_MAX - 1)
/* RTM_MULTIPATH --- array of struct rtnexthop.
*
* "struct rtnexthop" describes all necessary nexthop information,

View File

@ -116,6 +116,10 @@ int fdarray__filter(struct fdarray *fda, short revents,
return 0;
for (fd = 0; fd < fda->nr; ++fd) {
/*
* Explicitly bypass nonfilterable items (e.g. control descriptors).
* This ensures their fd, events, and revents remain completely untouched.
*/
if (fda->priv[fd].flags & fdarray_flag__nonfilterable)
continue;

View File

@ -79,8 +79,9 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
}
}
/* Ensure cpus only references valid PMU CPUs. */
if (!perf_cpu_map__has_any_cpu(evsel->cpus) &&
/* Ensure cpus only references valid PMU CPUs, except for uncore PMUs. */
if (!evsel->is_pmu_uncore &&
!perf_cpu_map__has_any_cpu(evsel->cpus) &&
!perf_cpu_map__is_subset(evsel->pmu_cpus, evsel->cpus)) {
struct perf_cpu_map *tmp = perf_cpu_map__intersect(evsel->pmu_cpus, evsel->cpus);

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;
/** Is the PMU for the event an uncore one? */
bool is_pmu_uncore;
/** 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

@ -200,7 +200,7 @@ void perf_mmap__read_done(struct perf_mmap *map)
/*
* Check if event was unmapped due to a POLLHUP/POLLERR.
*/
if (!refcount_read(&map->refcnt))
if (!refcount_read(&map->refcnt) || !map->overwrite)
return;
map->prev = perf_mmap__read_head(map);

View File

@ -21,3 +21,4 @@ IncludeCategories:
# Your Project's Other Headers
- Regex: '^".*"'
Priority: 4
AlignArrayOfStructures: Left

View File

@ -61,7 +61,6 @@ perf-util-y += arch/
perf-y += arch/
perf-test-y += arch/
perf-ui-y += ui/
perf-util-y += scripts/
gtk-y += ui/gtk/
@ -77,7 +76,9 @@ $(OUTPUT)%.shellcheck_log: %
$(call rule_mkdir)
$(Q)$(call echo-cmd,test)$(SHELLCHECK) "$<" > $@ || (cat $@ && rm $@ && false)
perf-y += $(SHELL_TEST_LOGS)
.PHONY: shellcheck
shellcheck: $(addprefix $(OUTPUT),$(SHELL_TEST_LOGS))
@:
ifdef MYPY
PY_TESTS := $(shell find python -type f -name '*.py')
@ -88,9 +89,11 @@ endif
$(OUTPUT)%.mypy_log: %
$(call rule_mkdir)
$(Q)$(call echo-cmd,test)mypy "$<" > $@ || (cat $@ && rm $@ && false)
$(Q)$(call echo-cmd,test)$(MYPY) "$<" > $@ || (cat $@ && rm $@ && false)
perf-y += $(MYPY_TEST_LOGS)
.PHONY: mypy
mypy: $(addprefix $(OUTPUT),$(MYPY_TEST_LOGS))
@:
ifdef PYLINT
PY_TESTS := $(shell find python -type f -name '*.py')
@ -101,6 +104,8 @@ endif
$(OUTPUT)%.pylint_log: %
$(call rule_mkdir)
$(Q)$(call echo-cmd,test)pylint "$<" > $@ || (cat $@ && rm $@ && false)
$(Q)$(call echo-cmd,test)$(PYLINT) "$<" > $@ || (cat $@ && rm $@ && false)
perf-y += $(PYLINT_TEST_LOGS)
.PHONY: pylint
pylint: $(addprefix $(OUTPUT),$(PYLINT_TEST_LOGS))
@:

View File

@ -41,6 +41,6 @@ while ($changed) {
while (my ($text, $included) = each %include) {
if (! exists $included{$text} &&
(my $base = $text) =~ s/\.txt$//) {
print "$base.html $base.xml : ", join(" ", keys %$included), "\n";
print "\$(OUTPUT)$base.html \$(OUTPUT)$base.xml : ", join(" ", keys %$included), "\n";
}
}

View File

@ -1,14 +1,14 @@
Database Export
===============
perf tool's python scripting engine:
perf tool's python module:
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/python.c
supports scripts:
supports standalone scripts:
tools/perf/scripts/python/export-to-sqlite.py
tools/perf/scripts/python/export-to-postgresql.py
tools/perf/python/export-to-sqlite.py
tools/perf/python/export-to-postgresql.py
which export data to a SQLite3 or PostgreSQL database.
@ -31,11 +31,5 @@ backward compatibility by testing for the presence of new tables and columns
before using them. e.g. function IsSelectable() in exported-sql-viewer.py
4. The export scripts themselves maintain forward compatibility (i.e. an existing
script will continue to work with new versions of perf) by accepting a variable
number of arguments (e.g. def call_return_table(*x)) i.e. perf can pass more
arguments which old scripts will ignore.
5. The scripting engine tests for the existence of script handler functions
before calling them. The scripting engine can also test for the support of new
or optional features by checking for the existence and value of script global
variables.
script will continue to work with new versions of perf) by querying event and
sample attributes dynamically from the perf Python module.

View File

@ -95,6 +95,9 @@ include::itrace.txt[]
--gtk:: Use the GTK interface.
--weights:: Show or hide (with `--no-weights`) weight columns in annotation output.
By default, weight columns are shown when samples contain non-zero weights.
-C::
--cpu=<cpu>:: Only report samples for the list of CPUs provided. Multiple CPUs can
be provided as a comma-separated list with no space: 0,1. Ranges of

View File

@ -58,6 +58,9 @@ SUBSYSTEM
'numa'::
NUMA scheduling and MM benchmarks.
'atomic'::
Atomic operation benchmarks.
'futex'::
Futex stressing benchmarks.
@ -283,6 +286,41 @@ SUITES FOR 'numa'
*mem*::
Suite for evaluating NUMA workloads.
SUITES FOR 'atomic'
~~~~~~~~~~~~~~~~~~~
*cas*::
Suite for evaluating compare-and-swap (CAS) atomic operations under
multi-threaded contention.
*inc*::
Suite for evaluating atomic fetch-add (increment) operations under
multi-threaded contention.
Options of *cas* and *inc*
^^^^^^^^^^^^^^^^^^^^^^^^^^
-T::
--threads=::
Number of threads contending for the shared counter (default: 2, or
1 on a single-CPU machine).
-R::
--runtime=::
Runtime of each repeat in seconds (default: 2).
The per-thread fastest/slowest/avg ops summary is only printed when
running with more than one thread.
The average throughput is annotated with its relative deviation
("+- x%"), i.e. the standard error of the mean over the measured
repeats. A small value means the average is reproducible; it does not
reflect per-thread fairness, which the per-thread ops summary shows.
Note that the cas benchmark counts successful compare-and-swap
operations only; retries and the loads between them are additional
atomic instructions not included in the ops/sec count, so cas and
inc throughputs are not directly comparable at the instruction
level.
SUITES FOR 'futex'
~~~~~~~~~~~~~~~~~~
*hash*::

View File

@ -107,6 +107,10 @@ REPORT OPTIONS
--stats::
Display only statistic tables and force stdio mode.
--function::
Display the function view and force stdio mode. This requires `iaddr`
in the cacheline coalescing fields and cannot be used with `--stats`.
--full-symbols::
Display full length of symbols.
@ -341,7 +345,7 @@ output fields set for cacheline offsets output:
Code address, Code symbol, Shared Object, Source line
dso - coalesced by shared object
By default the coalescing is setup with 'pid,iaddr'.
By default, coalescing uses `iaddr`.
STDIO OUTPUT
------------
@ -360,6 +364,10 @@ Following tables are displayed:
Shared Cache Line Distribution Pareto
- list of all accessed offsets for each cacheline
With `--function`, the cacheline and Pareto tables are replaced by a fully
expanded Shared Data Functions Table. Its three levels are the read-side
function, contending writer, and shared cacheline, as detailed below.
TUI OUTPUT
----------
The TUI output provides interactive interface to navigate
@ -374,8 +382,8 @@ Verbose mode also includes code addresses in function rows, and code addresses
remain available in the per-cacheline detail view ('d').
The function view requires `iaddr` in the cacheline coalescing fields. If
`--coalesce` omits it, TAB reports that the view is unavailable rather than
attributing already-coalesced samples to an arbitrary function.
`--coalesce` omits it, TAB or `--function` reports that the view is unavailable
rather than attributing already-coalesced samples to an arbitrary function.
Level 1: the read-side function, sorted by Cycles % (estimated load
cycles: HITM, peer-snoop and other-load cycles)

View File

@ -58,14 +58,13 @@ feature::
libLLVM / HAVE_LIBLLVM_SUPPORT
libnuma / HAVE_LIBNUMA_SUPPORT
libopencsd / HAVE_CSTRACE_SUPPORT
libperl / HAVE_LIBPERL_SUPPORT
libpfm4 / HAVE_LIBPFM
libpython / HAVE_LIBPYTHON_SUPPORT
libslang / HAVE_SLANG_SUPPORT
libtraceevent / HAVE_LIBTRACEEVENT
libunwind / HAVE_LIBUNWIND_SUPPORT
lzma / HAVE_LZMA_SUPPORT
numa_num_possible_cpus / HAVE_LIBNUMA_SUPPORT
python-module / HAVE_PYTHON_MODULE_SUPPORT
zlib / HAVE_ZLIB_SUPPORT
zstd / HAVE_ZSTD_SUPPORT

View File

@ -217,6 +217,16 @@ core.*::
Sets a timeout (in milliseconds) for parsing 'addr2line'
output. The default timeout is 5s.
hybrid-merge::
Merge matching events from all hybrid core PMUs into one display
by default. For example, if a wildcard expands to run on both p-cores and
e-cores, this aggregates them into a single view. This applies to
'perf report' and 'perf top', it is ignored with '--hierarchy' and
doesn't alter 'perf stat' where '--hybrid-merge' must be given
explicitly. As a default it is silently ignored when there is
nothing to merge, such as on a machine with a single core PMU,
whereas an explicit '--hybrid-merge' warns.
tui.*, gtk.*::
Subcommands that can be configured here are 'top', 'report' and 'annotate'.
These values are booleans, for example:

View File

@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'perf list' [<options>]
[hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]
'perf list' --tui [-- <ilist options>]
DESCRIPTION
-----------
@ -51,6 +52,15 @@ Output in JSON format.
--output=::
Output file name. By default output is written to stdout.
--tui::
Rather than printing the events, interactively browse the PMUs, events and
metrics in the terminal using the 'ilist' python script (see
linkperf:perf-script[1]). Selecting an event or metric shows its description
and counts it on each CPU. The script requires the perf python module and the
python 'textual' library. Other options are ignored, arguments after '--' are
passed to the script, for example 'perf list --tui -- -I 0.5' to update the
counts every 0.5 seconds.
[[EVENT_MODIFIERS]]
EVENT MODIFIERS
---------------

View File

@ -14,6 +14,10 @@ DESCRIPTION
-----------
"perf mem record" runs a command and gathers memory operation data
from it, into perf.data. Perf record options are accepted and are passed through.
It also requests the address (-d), the weight (-W, where supported) and the
CPU id (--sample-cpu) of every sampled access by default; the CPU id is what
lets per-sample analysis tell reads and writes to the same data from
different cores apart from same-CPU traffic.
"perf mem report" displays the result. It invokes perf report with the
right set of options to display a memory access profile. By default, loads

View File

@ -212,7 +212,7 @@ OPTIONS
The <value> can be one of:
<number> (for any term)
na, load, store, pfetch, exec (for mem_op)
l1, l2, l3, l4, cxl, io, any_cache, lfb, ram, pmem (for mem_lvl)
l0, l1, l2, l3, l4, cxl, io, any_cache, lfb, ram, pmem (for mem_lvl)
na, none, hit, miss, hitm, fwd, peer (for mem_snoop)
remote (for mem_remote)
na, locked (for mem_locked)
@ -293,7 +293,7 @@ OPTIONS
--call-graph::
Setup and enable call-graph (stack chain/backtrace) recording,
implies -g. Default is "fp" (for user space).
implies -g. Default is "fp" for user space (s390 uses "dwarf").
The unwinding method used for kernel space is dependent on the
unwinder used by the active kernel configuration, i.e
@ -329,6 +329,11 @@ OPTIONS
enable deferred user callchain which will collect user-space callchains
when the thread returns to the user space.
On s390, the "fp" method uses back chain instead of frame pointers,
which requires user space to maintain a back chain (e.g. compiler
option -mbackchain). Without a maintained back chain this produces
bogus call graphs. In that case use "dwarf" instead.
-q::
--quiet::
Don't print any warnings or messages, useful for scripting.
@ -480,9 +485,11 @@ Note that this feature may not be available on all processors.
-W::
--weight::
Enable weightened sampling. An additional weight is recorded per sample and can be
displayed with the weight and local_weight sort keys. This currently works for TSX
abort events and some memory events in precise mode on modern Intel CPUs.
Enable weighted sampling. One or more additional weights can be recorded per sample
and can be displayed with the weight, weight2, weight3 and local_weight sort keys.
Possible uses for weights are memory or instruction retirement latencies.
Support depends on the PMU and the event, as well as its configuration. Typically
it requires use of 'p'.
--namespaces::
Record events of type PERF_RECORD_NAMESPACES. This enables 'cgroup_id' sort key.
@ -513,12 +520,16 @@ Capture machine state (registers) at interrupt, i.e., on counter overflows for
each sample. List of captured registers depends on the architecture. This option
is off by default. It is possible to select the registers to sample using their
symbolic names, e.g. on x86, ax, si. To list the available registers use
--intr-regs=\?. To name registers, pass a comma separated list such as
--intr-regs=ax,bx. The list of register is architecture dependent.
--intr-regs=\?. On supported architectures, SIMD registers are displayed as
groups (e.g., on x86: XMM0-15,YMM0-15,ZMM0-31). To name registers, pass a comma
separated list such as --intr-regs=ax,bx,zmm. Please notice SIMD registers must
be assigned as a complete set, sampling individual SIMD registers (e.g., zmm0)
is not supported. The list of register is architecture dependent.
--user-regs::
Similar to -I, but capture user registers at sample time. To list the available
user registers use --user-regs=\?.
user registers use --user-regs=\?. For SIMD registers, only complete register
sets are allowed like -I.
--running-time::
Record running and enabled time for read events (:S)

View File

@ -29,6 +29,25 @@ OPTIONS
--quiet::
Do not show any warnings or messages. (Suppress -v)
--progress::
Show progress for each of the processing phases, printing the
percentage done and the current/total counts: the first phase
counts the bytes of the perf.data file processed so far, the
merge and sort phases count hist entries, e.g.:
Processing events... [ 42.3%] 4G / 10G
Merging related events... [ 7.1%] 1024 / 14387
Sorting events for output... [ 98.2%] 14132 / 14387
It is a no-op when using the TUI or GTK browsers, that already
present progress information, or when --quiet is used, that asks
for no messages at all.
--no-progress::
Do not show progress while processing the perf.data file. It
also turns off the progress the TUI and GTK browsers present,
which is their own.
-n::
--show-nr-samples::
Show the number of samples for each symbol
@ -64,6 +83,9 @@ OPTIONS
--symbol-filter=::
Only show symbols that match (partially) with this filter.
--weights:: Show or hide (with `--no-weights`) weight columns in annotation output.
By default, weight columns are shown when samples contain non-zero weights.
-U::
--hide-unresolved::
Only display entries resolved to a symbol.
@ -351,7 +373,10 @@ OPTIONS
requires a tty, if one is not present, as when piping to other
commands, the stdio interface is used.
--gtk:: Use the GTK2 interface.
--gtk:: Use the GTK4 interface.
--weights:: Show or hide (with `--no-weights`) weight columns in annotation output.
By default, weight columns are shown when samples contain non-zero weights.
-k::
--vmlinux=<file>::
@ -572,6 +597,11 @@ include::itrace.txt[]
--raw-trace::
When displaying traceevent output, do not use print fmt or plugins.
--hybrid-merge::
Merge matching events from all hybrid core PMUs into one
display. For example, if a wildcard expands to run on both p-cores and
e-cores, this aggregates them into a single view.
-H::
--hierarchy::
Enable hierarchical output. In the hierarchy mode, each sort key groups

View File

@ -95,8 +95,10 @@ There are several variants of 'perf sched':
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`.
Note: Reports reject incomplete snapshots and mismatched CPU or domain IDs.
Topology changes that retain the same IDs, including CPUs going offline
and returning online between snapshots, cannot be detected and may still
produce incorrect results.
Example usage:
perf sched stats record -- sleep 1

View File

@ -1,216 +0,0 @@
perf-script-perl(1)
===================
NAME
----
perf-script-perl - Process trace data with a Perl script
SYNOPSIS
--------
[verse]
'perf script' [-s [Perl]:script[.pl] ]
DESCRIPTION
-----------
This perf script option is used to process perf script data using perf's
built-in Perl interpreter. It reads and processes the input file and
displays the results of the trace analysis implemented in the given
Perl script, if any.
STARTER SCRIPTS
---------------
You can avoid reading the rest of this document by running 'perf script
-g perl' in the same directory as an existing perf.data trace file.
That will generate a starter script containing a handler for each of
the event types in the trace file; it simply prints every available
field for each event in the trace file.
You can also look at the existing scripts in
~/libexec/perf-core/scripts/perl for typical examples showing how to
do basic things like aggregate event data, print results, etc. Also,
the check-perf-script.pl script, while not interesting for its results,
attempts to exercise all of the main scripting features.
EVENT HANDLERS
--------------
When perf script is invoked using a trace script, a user-defined
'handler function' is called for each event in the trace. If there's
no handler function defined for a given event type, the event is
ignored (or passed to a 'trace_unhandled' function, see below) and the
next event is processed.
Most of the event's field values are passed as arguments to the
handler function; some of the less common ones aren't - those are
available as calls back into the perf executable (see below).
As an example, the following perf record command can be used to record
all sched_wakeup events in the system:
# perf record -a -e sched:sched_wakeup
Traces meant to be processed using a script should be recorded with
the above option: -a to enable system-wide collection.
The format file for the sched_wakeup event defines the following fields
(see /sys/kernel/tracing/events/sched/sched_wakeup/format):
----
format:
field:unsigned short common_type;
field:unsigned char common_flags;
field:unsigned char common_preempt_count;
field:int common_pid;
field:char comm[TASK_COMM_LEN];
field:pid_t pid;
field:int prio;
field:int success;
field:int target_cpu;
----
The handler function for this event would be defined as:
----
sub sched::sched_wakeup
{
my ($event_name, $context, $common_cpu, $common_secs,
$common_nsecs, $common_pid, $common_comm,
$comm, $pid, $prio, $success, $target_cpu) = @_;
}
----
The handler function takes the form subsystem::event_name.
The $common_* arguments in the handler's argument list are the set of
arguments passed to all event handlers; some of the fields correspond
to the common_* fields in the format file, but some are synthesized,
and some of the common_* fields aren't common enough to to be passed
to every event as arguments but are available as library functions.
Here's a brief description of each of the invariant event args:
$event_name the name of the event as text
$context an opaque 'cookie' used in calls back into perf
$common_cpu the cpu the event occurred on
$common_secs the secs portion of the event timestamp
$common_nsecs the nsecs portion of the event timestamp
$common_pid the pid of the current task
$common_comm the name of the current process
All of the remaining fields in the event's format file have
counterparts as handler function arguments of the same name, as can be
seen in the example above.
The above provides the basics needed to directly access every field of
every event in a trace, which covers 90% of what you need to know to
write a useful trace script. The sections below cover the rest.
SCRIPT LAYOUT
-------------
Every perf script Perl script should start by setting up a Perl module
search path and 'use'ing a few support modules (see module
descriptions below):
----
use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core;
use Perf::Trace::Context;
use Perf::Trace::Util;
----
The rest of the script can contain handler functions and support
functions in any order.
Aside from the event handler functions discussed above, every script
can implement a set of optional functions:
*trace_begin*, if defined, is called before any event is processed and
gives scripts a chance to do setup tasks:
----
sub trace_begin
{
}
----
*trace_end*, if defined, is called after all events have been
processed and gives scripts a chance to do end-of-script tasks, such
as display results:
----
sub trace_end
{
}
----
*trace_unhandled*, if defined, is called after for any event that
doesn't have a handler explicitly defined for it. The standard set
of common arguments are passed into it:
----
sub trace_unhandled
{
my ($event_name, $context, $common_cpu, $common_secs,
$common_nsecs, $common_pid, $common_comm) = @_;
}
----
The remaining sections provide descriptions of each of the available
built-in perf script Perl modules and their associated functions.
AVAILABLE MODULES AND FUNCTIONS
-------------------------------
The following sections describe the functions and variables available
via the various Perf::Trace::* Perl modules. To use the functions and
variables from the given module, add the corresponding 'use
Perf::Trace::XXX' line to your perf script script.
Perf::Trace::Core Module
~~~~~~~~~~~~~~~~~~~~~~~~
These functions provide some essential functions to user scripts.
The *flag_str* and *symbol_str* functions provide human-readable
strings for flag and symbolic fields. These correspond to the strings
and values parsed from the 'print fmt' fields of the event format
files:
flag_str($event_name, $field_name, $field_value) - returns the string representation corresponding to $field_value for the flag field $field_name of event $event_name
symbol_str($event_name, $field_name, $field_value) - returns the string representation corresponding to $field_value for the symbolic field $field_name of event $event_name
Perf::Trace::Context Module
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some of the 'common' fields in the event format file aren't all that
common, but need to be made accessible to user scripts nonetheless.
Perf::Trace::Context defines a set of functions that can be used to
access this data in the context of the current event. Each of these
functions expects a $context variable, which is the same as the
$context variable passed into every event handler as the second
argument.
common_pc($context) - returns common_preempt count for the current event
common_flags($context) - returns common_flags for the current event
common_lock_depth($context) - returns common_lock_depth for the current event
Perf::Trace::Util Module
~~~~~~~~~~~~~~~~~~~~~~~~
Various utility functions for use with perf script:
nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
nsecs_secs($nsecs) - returns whole secs portion given nsecs
nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
nsecs_str($nsecs) - returns printable string in the form secs.nsecs
avg($total, $n) - returns average given a sum and a total number of values
SEE ALSO
--------
linkperf:perf-script[1]

View File

@ -3,676 +3,182 @@ perf-script-python(1)
NAME
----
perf-script-python - Process trace data with a Python script
perf-script-python - Process trace data with a Python script using perf module
SYNOPSIS
--------
[verse]
'perf script' [-s [Python]:script[.py] ]
'perf script' <script>.py
DESCRIPTION
-----------
This perf script option is used to process perf script data using perf's
built-in Python interpreter. It reads and processes the input file and
displays the results of the trace analysis implemented in the given
Python script, if any.
This document describes how to use the `perf` Python module to process
trace data recorded by `perf record`.
With the removal of embedded Python interpreter from `perf`, scripts
are now run as standalone Python programs that import the `perf`
module to access trace data. Symbol configuration options (`--vmlinux`,
`--kallsyms`, and `--symfs`) and `--itrace` options passed to `perf script`
are forwarded via `PERF_SYMBOL_*` and `PERF_ITRACE` environment variables
to `perf.session`, and can also be passed directly to `perf.session`.
Trace filtering command-line
options (`-C`, `-c`, `--pid`, `--tid`, `--time`, `--dlfilter`, `--dlarg`) passed
to `perf script` are not applied to standalone scripts.
A QUICK EXAMPLE
---------------
This section shows the process, start to finish, of creating a working
Python script that aggregates and extracts useful information from a
raw perf script stream. You can avoid reading the rest of this
document if an example is enough for you; the rest of the document
provides more details on each step and lists the library functions
available to script writers.
This section shows how to create a simple Python script that reads a
`perf.data` file and prints event information.
This example actually details the steps that were used to create the
'syscall-counts' script you see when you list the available perf script
scripts via 'perf script -l'. As such, this script also shows how to
integrate your script into the list of general-purpose 'perf script'
scripts listed by that command.
Create a file named `print_events.py` with the following content:
The syscall-counts script is a simple script, but demonstrates all the
basic ideas necessary to create a useful script. Here's an example
of its output (syscall names are not yet supported, they will appear
as numbers):
#!/usr/bin/env python3
import perf
----
syscall events:
def process_event(sample):
print(f"Event: {sample.evsel} on CPU {sample.sample_cpu} at {sample.sample_time}")
event count
---------------------------------------- -----------
sys_write 455067
sys_getdents 4072
sys_close 3037
sys_swapoff 1769
sys_read 923
sys_sched_setparam 826
sys_open 331
sys_newfstat 326
sys_mmap 217
sys_munmap 216
sys_futex 141
sys_select 102
sys_poll 84
sys_setitimer 12
sys_writev 8
15 8
sys_lseek 7
sys_rt_sigprocmask 6
sys_wait4 3
sys_ioctl 3
sys_set_robust_list 1
sys_exit 1
56 1
sys_access 1
----
# Open the session with perf.data file
session = perf.session(perf.data("perf.data"), sample=process_event)
Basically our task is to keep a per-syscall tally that gets updated
every time a system call occurs in the system. Our script will do
that, but first we need to record the data that will be processed by
that script. Theoretically, there are a couple of ways we could do
that:
# Process all events
session.process_events()
- we could enable every event under the tracing/events/syscalls
directory, but this is over 600 syscalls, well beyond the number
allowable by perf. These individual syscall events will however be
useful if we want to later use the guidance we get from the
general-purpose scripts to drill down and get more detail about
individual syscalls of interest.
Make the script executable:
$ chmod +x print_events.py
- we can enable the sys_enter and/or sys_exit syscalls found under
tracing/events/raw_syscalls. These are called for all syscalls; the
'id' field can be used to distinguish between individual syscall
numbers.
Record some data:
$ perf record -a sleep 1
For this script, we only need to know that a syscall was entered; we
don't care how it exited, so we'll use 'perf record' to record only
the sys_enter events:
Run the script:
$ perf script print_events.py
----
# perf record -a -e raw_syscalls:sys_enter
Or run it directly with Python, ensuring `perf.so` is in your `PYTHONPATH`:
$ PYTHONPATH=/path/to/perf/python python3 print_events.py
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
----
The options basically say to collect data for every syscall event
system-wide and multiplex the per-cpu output into a single stream.
That single stream will be recorded in a file in the current directory
called perf.data.
Once we have a perf.data file containing our data, we can use the -g
'perf script' option to generate a Python script that will contain a
callback handler for each event type found in the perf.data trace
stream (for more details, see the STARTER SCRIPTS section).
----
# perf script -g python
generated Python script: perf-script.py
The output file created also in the current directory is named
perf-script.py. Here's the file in its entirety:
# perf script event handlers, generated by perf script -g python
# Licensed under the terms of the GNU GPL License version 2
# The common_* event handler fields are the most useful fields common to
# all events. They don't necessarily correspond to the 'common_*' fields
# in the format files. Those fields not available as handler params can
# be retrieved using Python functions of the form common_*(context).
# See the perf-script-python Documentation for the list of available functions.
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
def trace_begin():
print "in trace_begin"
def trace_end():
print "in trace_end"
def raw_syscalls__sys_enter(event_name, context, common_cpu,
common_secs, common_nsecs, common_pid, common_comm,
id, args):
print_header(event_name, common_cpu, common_secs, common_nsecs,
common_pid, common_comm)
print "id=%d, args=%s\n" % \
(id, args),
def trace_unhandled(event_name, context, event_fields_dict):
print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
def print_header(event_name, cpu, secs, nsecs, pid, comm):
print "%-20s %5u %05u.%09u %8u %-20s " % \
(event_name, cpu, secs, nsecs, pid, comm),
----
At the top is a comment block followed by some import statements and a
path append which every perf script script should include.
Following that are a couple generated functions, trace_begin() and
trace_end(), which are called at the beginning and the end of the
script respectively (for more details, see the SCRIPT_LAYOUT section
below).
Following those are the 'event handler' functions generated one for
every event in the 'perf record' output. The handler functions take
the form subsystem\__event_name, and contain named parameters, one for
each field in the event; in this case, there's only one event,
raw_syscalls__sys_enter(). (see the EVENT HANDLERS section below for
more info on event handlers).
The final couple of functions are, like the begin and end functions,
generated for every script. The first, trace_unhandled(), is called
every time the script finds an event in the perf.data file that
doesn't correspond to any event handler in the script. This could
mean either that the record step recorded event types that it wasn't
really interested in, or the script was run against a trace file that
doesn't correspond to the script.
The script generated by -g option simply prints a line for each
event found in the trace stream i.e. it basically just dumps the event
and its parameter values to stdout. The print_header() function is
simply a utility function used for that purpose. Let's rename the
script and run it to see the default output:
----
# mv perf-script.py syscall-counts.py
# perf script -s syscall-counts.py
raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args=
raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args=
raw_syscalls__sys_enter 1 00840.847620860 7506 perf id=1, args=
raw_syscalls__sys_enter 1 00840.847710478 6533 npviewer.bin id=78, args=
raw_syscalls__sys_enter 1 00840.847719204 6533 npviewer.bin id=142, args=
raw_syscalls__sys_enter 1 00840.847755445 6533 npviewer.bin id=3, args=
raw_syscalls__sys_enter 1 00840.847775601 6533 npviewer.bin id=3, args=
raw_syscalls__sys_enter 1 00840.847781820 6533 npviewer.bin id=3, args=
.
.
.
----
Of course, for this script, we're not interested in printing every
trace event, but rather aggregating it in a useful way. So we'll get
rid of everything to do with printing as well as the trace_begin() and
trace_unhandled() functions, which we won't be using. That leaves us
with this minimalistic skeleton:
----
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
def trace_end():
print "in trace_end"
def raw_syscalls__sys_enter(event_name, context, common_cpu,
common_secs, common_nsecs, common_pid, common_comm,
id, args):
----
In trace_end(), we'll simply print the results, but first we need to
generate some results to print. To do that we need to have our
sys_enter() handler do the necessary tallying until all events have
been counted. A hash table indexed by syscall id is a good way to
store that information; every time the sys_enter() handler is called,
we simply increment a count associated with that hash entry indexed by
that syscall id:
----
syscalls = autodict()
try:
syscalls[id] += 1
except TypeError:
syscalls[id] = 1
----
The syscalls 'autodict' object is a special kind of Python dictionary
(implemented in Core.py) that implements Perl's 'autovivifying' hashes
in Python i.e. with autovivifying hashes, you can assign nested hash
values without having to go to the trouble of creating intermediate
levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
the intermediate hash levels and finally assign the value 1 to the
hash entry for 'id' (because the value being assigned isn't a hash
object itself, the initial value is assigned in the TypeError
exception. Well, there may be a better way to do this in Python but
that's what works for now).
Putting that code into the raw_syscalls__sys_enter() handler, we
effectively end up with a single-level dictionary keyed on syscall id
and having the counts we've tallied as values.
The print_syscall_totals() function iterates over the entries in the
dictionary and displays a line for each entry containing the syscall
name (the dictionary keys contain the syscall ids, which are passed to
the Util function syscall_name(), which translates the raw syscall
numbers to the corresponding syscall name strings). The output is
displayed after all the events in the trace have been processed, by
calling the print_syscall_totals() function from the trace_end()
handler called at the end of script processing.
The final script producing the output shown above is shown in its
entirety below (syscall_name() helper is not yet available, you can
only deal with id's for now):
----
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
from Util import *
syscalls = autodict()
def trace_end():
print_syscall_totals()
def raw_syscalls__sys_enter(event_name, context, common_cpu,
common_secs, common_nsecs, common_pid, common_comm,
id, args):
try:
syscalls[id] += 1
except TypeError:
syscalls[id] = 1
def print_syscall_totals():
if for_comm is not None:
print "\nsyscall events for %s:\n\n" % (for_comm),
else:
print "\nsyscall events:\n\n",
print "%-40s %10s\n" % ("event", "count"),
print "%-40s %10s\n" % ("----------------------------------------", \
"-----------"),
for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
reverse = True):
print "%-40s %10d\n" % (syscall_name(id), val),
----
The script can be run just as before:
# perf script -s syscall-counts.py
So those are the essential steps in writing and running a script. The
process can be generalized to any tracepoint or set of tracepoints
you're interested in - basically find the tracepoint(s) you're
interested in by looking at the list of available events shown by
'perf list' and/or look in /sys/kernel/tracing/events/ for
detailed event and field info, record the corresponding trace data
using 'perf record', passing it the list of interesting events,
generate a skeleton script using 'perf script -g python' and modify the
code to aggregate and display it for your particular needs.
After you've done that you may end up with a general-purpose script
that you want to keep around and have available for future use. By
writing a couple of very simple shell scripts and putting them in the
right place, you can have your script listed alongside the other
scripts listed by the 'perf script -l' command e.g.:
----
# perf script -l
List of available trace scripts:
wakeup-latency system-wide min/max/avg wakeup latency
rw-by-file <comm> r/w activity for a program, by file
rw-by-pid system-wide r/w activity
----
A nice side effect of doing this is that you also then capture the
probably lengthy 'perf record' command needed to record the events for
the script.
To have the script appear as a 'built-in' script, you write two simple
scripts, one for recording and one for 'reporting'.
The 'record' script is a shell script with the same base name as your
script, but with -record appended. The shell script should be put
into the perf/scripts/python/bin directory in the kernel source tree.
In that script, you write the 'perf record' command-line needed for
your script:
----
# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
#!/bin/bash
perf record -a -e raw_syscalls:sys_enter
----
The 'report' script is also a shell script with the same base name as
your script, but with -report appended. It should also be located in
the perf/scripts/python/bin directory. In that script, you write the
'perf script -s' command-line needed for running your script:
----
# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
#!/bin/bash
# description: system-wide syscall counts
perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py
----
Note that the location of the Python script given in the shell script
is in the libexec/perf-core/scripts/python directory - this is where
the script will be copied by 'make install' when you install perf.
For the installation to install your script there, your script needs
to be located in the perf/scripts/python directory in the kernel
source tree:
----
# ls -al kernel-source/tools/perf/scripts/python
total 32
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
----
Once you've done that (don't forget to do a new 'make install',
otherwise your script won't show up at run-time), 'perf script -l'
should show a new entry for your script:
----
# perf script -l
List of available trace scripts:
wakeup-latency system-wide min/max/avg wakeup latency
rw-by-file <comm> r/w activity for a program, by file
rw-by-pid system-wide r/w activity
syscall-counts system-wide syscall counts
----
You can now perform the record step via 'perf script record':
# perf script record syscall-counts
and display the output using 'perf script report':
# perf script report syscall-counts
STARTER SCRIPTS
THE PERF MODULE
---------------
You can quickly get started writing a script for a particular set of
trace data by generating a skeleton script using 'perf script -g
python' in the same directory as an existing perf.data trace file.
That will generate a starter script containing a handler for each of
the event types in the trace file; it simply prints every available
field for each event in the trace file.
The `perf` module provides several classes and functions to interact
with trace data.
You can also look at the existing scripts in
~/libexec/perf-core/scripts/python for typical examples showing how to
do basic things like aggregate event data, print results, etc. Also,
the check-perf-script.py script, while not interesting for its results,
attempts to exercise all of the main scripting features.
Module Functions
~~~~~~~~~~~~~~~~
EVENT HANDLERS
--------------
- `config_get(name)`: Get a perf config value.
- `metrics()`: Returns a list of metrics represented as string values in dictionaries.
- `tracepoint(sys, name)`: Get the tracepoint ID for a given subsystem and event name.
- `parse_events(evlist_str, cpus=None, threads=None)`: Parse a string of events and return an `evlist`.
- `parse_metrics(metrics_str, pmu=None, cpus=None, threads=None)`: Parse a string of metrics or metric groups and return an `evlist`.
- `pmus()`: Returns a sequence of PMUs.
- `syscall_name(id, elf_machine=0)`: Convert a syscall number to its name.
- `syscall_id(name, elf_machine=0)`: Convert a syscall name to its number.
When perf script is invoked using a trace script, a user-defined
'handler function' is called for each event in the trace. If there's
no handler function defined for a given event type, the event is
ignored (or passed to a 'trace_unhandled' function, see below) and the
next event is processed.
perf.pmu
~~~~~~~~
Most of the event's field values are passed as arguments to the
handler function; some of the less common ones aren't - those are
available as calls back into the perf executable (see below).
Represents a Performance Monitoring Unit.
As an example, the following perf record command can be used to record
all sched_wakeup events in the system:
- `events()`: Returns a sequence of events encoded as dictionaries.
- `name()`: Name of the PMU including suffixes.
# perf record -a -e sched:sched_wakeup
perf.evlist
~~~~~~~~~~~
Traces meant to be processed using a script should be recorded with
the above option: -a to enable system-wide collection.
Represents a list of event selectors.
The format file for the sched_wakeup event defines the following fields
(see /sys/kernel/tracing/events/sched/sched_wakeup/format):
- `all_cpus()`: CPU map union of all evsel CPU maps.
- `metrics()`: List of metric names within the evlist.
- `compute_metric(name, cpu, thread)`: Compute metric for given name, cpu and thread.
- `mmap(pages=128, overwrite=False)`: mmap the file descriptor table.
- `open()`: open the file descriptors.
- `close()`: close the file descriptors.
- `poll(timeout=-1)`: poll the file descriptor table.
- `get_pollfd()`: get the poll file descriptor table.
- `add(evsel)`: adds an event selector to the list.
- `read_on_cpu(cpu, sample_id_all=True)`: reads an event from the specified CPU ring buffer.
- `config()`: Apply default record options to the evlist.
- `disable()`: Disable the evsels in the evlist.
- `enable()`: Enable the evsels in the evlist.
----
format:
field:unsigned short common_type;
field:unsigned char common_flags;
field:unsigned char common_preempt_count;
field:int common_pid;
perf.evsel
~~~~~~~~~~
field:char comm[TASK_COMM_LEN];
field:pid_t pid;
field:int prio;
field:int success;
field:int target_cpu;
----
Represents an event selector.
The handler function for this event would be defined as:
- `open()`: open the event selector file descriptor table.
- `cpus()`: CPUs the event is to be used with.
- `threads()`: threads the event is to be used with.
- `read(cpu, thread)`: read counters. Returns a count object with `val`, `ena`, and `run` attributes.
----
def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
common_nsecs, common_pid, common_comm,
comm, pid, prio, success, target_cpu):
pass
----
perf.session
~~~~~~~~~~~~
The handler function takes the form subsystem__event_name.
Manages a trace session.
The common_* arguments in the handler's argument list are the set of
arguments passed to all event handlers; some of the fields correspond
to the common_* fields in the format file, but some are synthesized,
and some of the common_* fields aren't common enough to to be passed
to every event as arguments but are available as library functions.
- `__init__(data, sample=None, stat=None, context_switch=None, call_return=None, itrace=None, vmlinux=None, kallsyms=None, symfs=None)`: Creates a new session. `data` is a `perf.data` object. `sample` is a callback function called for each sample event. `vmlinux`, `kallsyms`, and `symfs` configure symbol resolution paths.
- `process_events()`: Reads the trace data and calls the sample callback for each event.
- `find_thread(pid, tid=-1)`: Returns the thread associated with a PID/TID.
- `e_machine`: ELF machine architecture ID (`EM_*`) of the session.
- `is_64_bit`: Boolean indicating whether the traced session is 64-bit.
Here's a brief description of each of the invariant event args:
perf.data
~~~~~~~~~
event_name the name of the event as text
context an opaque 'cookie' used in calls back into perf
common_cpu the cpu the event occurred on
common_secs the secs portion of the event timestamp
common_nsecs the nsecs portion of the event timestamp
common_pid the pid of the current task
common_comm the name of the current process
Represents a trace file.
All of the remaining fields in the event's format file have
counterparts as handler function arguments of the same name, as can be
seen in the example above.
- `__init__(path=None, fd=-1)`: Opens a trace file.
The above provides the basics needed to directly access every field of
every event in a trace, which covers 90% of what you need to know to
write a useful trace script. The sections below cover the rest.
Sample Object
~~~~~~~~~~~~~
SCRIPT LAYOUT
-------------
Passed to the `sample` callback function in `perf.session` (or returned by `evlist.read_on_cpu()`).
Every perf script Python script should start by setting up a Python
module search path and 'import'ing a few support modules (see module
descriptions below):
- `evsel`: The event selector (`perf.evsel` object; `str(sample.evsel)` gives the event name).
- `sample_cpu`: The CPU on which the event occurred.
- `sample_time`: The timestamp of the event in nanoseconds.
- `sample_pid`: The PID of the process.
- `sample_tid`: The TID of the thread.
- `sample_ip`: The sampled instruction pointer.
- `sample_addr`: The sampled target/data address.
- `sample_period`: The sample period.
- `machine_pid`: The guest VM machine PID (`0` for host).
- `vcpu`: The virtual CPU number for guest events.
- `raw_buf`: Raw buffer (`bytes`) containing event-specific data.
- `dso`: Short name of the resolved DSO for `sample_ip`.
- `dso_long_name`: Full path/long name of the resolved DSO for `sample_ip`.
- `dso_bid`: Build ID of the resolved DSO.
- `symbol`: Resolved symbol name for `sample_ip`.
- `sym_start`: Start address of the resolved symbol.
- `sym_end`: End address of the resolved symbol.
- `sym_offset`: Offset of `sample_ip` within the resolved symbol (or `None` if unresolved).
- `addr_dso`: Resolved DSO name for `sample_addr` (or `None`).
- `addr_symbol`: Resolved symbol name for `sample_addr` (or `None`).
- `addr_sym_offset`: Offset of `sample_addr` within `addr_symbol` (or `None`).
- `branch_type`: Branch type flags (`PERF_IP_FLAG_*` masked with `PERF_BRANCH_MASK`).
- `in_tx`: `1` if the sample occurred inside a hardware transaction, else `0`.
- `flags`: Raw sample flags (`PERF_IP_FLAG_*`).
- `transaction`: Transaction abort/status code.
- `brstack`: Sequence of branch stack entries (`from_ip`, `to_ip`, `mispred`, `predicted`, `in_tx`, `abort`, `cycles`, `type`), or `None`.
- `callchain`: Sequence of callchain nodes (`ip`, `symbol`, `dso`), or `None`.
- `srccode(addr=sample_ip)`: Returns a `(filename, line_number, srcline)` tuple for `addr` (defaults to `sample_ip`), or `None`.
- `insn()`: Returns the raw instruction `bytes` for the sample, or `None`.
- Dynamic tracepoint fields: For tracepoint events (`PERF_TYPE_TRACEPOINT`), tracepoint format fields can be accessed directly as attributes on the sample object (e.g. `sample.prev_pid`, `sample.id`, `sample.common_flags`).
----
import os
import sys
COUNTER AND METRIC APIS
-----------------------
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
The following APIs are used in `tools/perf/python/ilist.py` for
interactive listing and reading of counters and metrics:
from perf_trace_context import *
from Core import *
----
The rest of the script can contain handler functions and support
functions in any order.
Aside from the event handler functions discussed above, every script
can implement a set of optional functions:
*trace_begin*, if defined, is called before any event is processed and
gives scripts a chance to do setup tasks:
----
def trace_begin():
pass
----
*trace_end*, if defined, is called after all events have been
processed and gives scripts a chance to do end-of-script tasks, such
as display results:
----
def trace_end():
pass
----
*trace_unhandled*, if defined, is called after for any event that
doesn't have a handler explicitly defined for it. The standard set
of common arguments are passed into it:
----
def trace_unhandled(event_name, context, event_fields_dict):
pass
----
*process_event*, if defined, is called for any non-tracepoint event
----
def process_event(param_dict):
pass
----
*context_switch*, if defined, is called for any context switch
----
def context_switch(ts, cpu, pid, tid, np_pid, np_tid, machine_pid, out, out_preempt, *x):
pass
----
*auxtrace_error*, if defined, is called for any AUX area tracing error
----
def auxtrace_error(typ, code, cpu, pid, tid, ip, ts, msg, cpumode, *x):
pass
----
The remaining sections provide descriptions of each of the available
built-in perf script Python modules and their associated functions.
AVAILABLE MODULES AND FUNCTIONS
-------------------------------
The following sections describe the functions and variables available
via the various perf script Python modules. To use the functions and
variables from the given module, add the corresponding 'from XXXX
import' line to your perf script script.
Core.py Module
~~~~~~~~~~~~~~
These functions provide some essential functions to user scripts.
The *flag_str* and *symbol_str* functions provide human-readable
strings for flag and symbolic fields. These correspond to the strings
and values parsed from the 'print fmt' fields of the event format
files:
flag_str(event_name, field_name, field_value) - returns the string representation corresponding to field_value for the flag field field_name of event event_name
symbol_str(event_name, field_name, field_value) - returns the string representation corresponding to field_value for the symbolic field field_name of event event_name
The *autodict* function returns a special kind of Python
dictionary that implements Perl's 'autovivifying' hashes in Python
i.e. with autovivifying hashes, you can assign nested hash values
without having to go to the trouble of creating intermediate levels if
they don't exist.
autodict() - returns an autovivifying dictionary instance
perf_trace_context Module
~~~~~~~~~~~~~~~~~~~~~~~~~
Some of the 'common' fields in the event format file aren't all that
common, but need to be made accessible to user scripts nonetheless.
perf_trace_context defines a set of functions that can be used to
access this data in the context of the current event. Each of these
functions expects a context variable, which is the same as the
context variable passed into every tracepoint event handler as the second
argument. For non-tracepoint events, the context variable is also present
as perf_trace_context.perf_script_context .
common_pc(context) - returns common_preempt count for the current event
common_flags(context) - returns common_flags for the current event
common_lock_depth(context) - returns common_lock_depth for the current event
perf_sample_insn(context) - returns the machine code instruction
perf_set_itrace_options(context, itrace_options) - set --itrace options if they have not been set already
perf_sample_srcline(context) - returns source_file_name, line_number
perf_sample_srccode(context) - returns source_file_name, line_number, source_line
perf_config_get(config_name) - returns the value of the named config item, or None if unset
Util.py Module
~~~~~~~~~~~~~~
Various utility functions for use with perf script:
nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
nsecs_secs(nsecs) - returns whole secs portion given nsecs
nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
nsecs_str(nsecs) - returns printable string in the form secs.nsecs
avg(total, n) - returns average given a sum and a total number of values
SUPPORTED FIELDS
----------------
Currently supported fields:
ev_name, comm, id, stream_id, pid, tid, cpu, ip, time, period, phys_addr,
addr, symbol, symoff, dso, time_enabled, time_running, values, callchain,
brstack, brstacksym, datasrc, datasrc_decode, iregs, uregs,
weight, transaction, raw_buf, attr, cpumode.
Fields that may also be present:
flags - sample flags
flags_disp - sample flags display
insn_cnt - instruction count for determining instructions-per-cycle (IPC)
cyc_cnt - cycle count for determining IPC
addr_correlates_sym - addr can correlate to a symbol
addr_dso - addr dso
addr_symbol - addr symbol
addr_symoff - addr symbol offset
Some fields have sub items:
brstack:
from, to, from_dsoname, to_dsoname, mispred,
predicted, in_tx, abort, cycles.
brstacksym:
items: from, to, pred, in_tx, abort (converted string)
For example,
We can use this code to print brstack "from", "to", "cycles".
if 'brstack' in dict:
for entry in dict['brstack']:
print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"])
- `perf.pmus()`: Used to get all available PMUs.
- `pmu.events()`: Used to get all events for a specific PMU.
- `perf.metrics()`: Used to get all available metrics.
- `perf.parse_metrics(metric_name, pmu)`: Used to parse a metric and get an `evlist`.
- `evlist.compute_metric(metric_name, cpu, thread)`: Used to compute a metric value for a specific CPU and thread.
- `evsel.read(cpu, thread)`: Used to read raw counter values.
SEE ALSO
--------

View File

@ -9,10 +9,7 @@ SYNOPSIS
--------
[verse]
'perf script' [<options>]
'perf script' [<options>] record <script> [<record-options>] <command>
'perf script' [<options>] report <script> [script-args]
'perf script' [<options>] <script> <required-script-args> [<record-options>] <command>
'perf script' [<options>] <top-script> [script-args]
'perf script' [<options>] <script> [script-args]
DESCRIPTION
-----------
@ -23,58 +20,12 @@ There are several variants of perf script:
'perf script' to see a detailed trace of the workload that was
recorded.
You can also run a set of pre-canned scripts that aggregate and
summarize the raw trace data in various ways (the list of scripts is
available via 'perf script -l'). The following variants allow you to
record and run those scripts:
'perf script record <script> <command>' to record the events required
for 'perf script report'. <script> is the name displayed in the
output of 'perf script --list' i.e. the actual script name minus any
language extension. If <command> is not specified, the events are
recorded using the -a (system-wide) 'perf record' option.
'perf script report <script> [args]' to run and display the results
of <script>. <script> is the name displayed in the output of 'perf
script --list' i.e. the actual script name minus any language
extension. The perf.data output from a previous run of 'perf script
record <script>' is used and should be present for this command to
succeed. [args] refers to the (mainly optional) args expected by
the script.
'perf script <script> <required-script-args> <command>' to both
record the events required for <script> and to run the <script>
using 'live-mode' i.e. without writing anything to disk. <script>
is the name displayed in the output of 'perf script --list' i.e. the
actual script name minus any language extension. If <command> is
not specified, the events are recorded using the -a (system-wide)
'perf record' option. If <script> has any required args, they
should be specified before <command>. This mode doesn't allow for
optional script args to be specified; if optional script args are
desired, they can be specified using separate 'perf script record'
and 'perf script report' commands, with the stdout of the record step
piped to the stdin of the report script, using the '-o -' and '-i -'
options of the corresponding commands.
'perf script <top-script>' to both record the events required for
<top-script> and to run the <top-script> using 'live-mode'
i.e. without writing anything to disk. <top-script> is the name
displayed in the output of 'perf script --list' i.e. the actual
script name minus any language extension; a <top-script> is defined
as any script name ending with the string 'top'.
[<record-options>] can be passed to the record steps of 'perf script
record' and 'live-mode' variants; this isn't possible however for
<top-script> 'live-mode' or 'perf script report' variants.
See the 'SEE ALSO' section for links to language-specific
information on how to write and run your own trace scripts.
You can also run standalone scripts that aggregate and summarize the
raw trace data in various ways (the list of scripts is available via
'perf script -l').
OPTIONS
-------
<command>...::
Any command you can specify in a shell.
-D::
--dump-raw-trace=::
Display verbose dump of the trace data.
@ -90,19 +41,6 @@ OPTIONS
--list=::
Display a list of available trace scripts.
-s ['lang']::
--script=::
Process trace data with the given script ([lang]:script[.ext]).
If the string 'lang' is specified in place of a script name, a
list of supported languages will be displayed instead.
-g::
--gen-script=::
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.
Refer linkperf:perf-dlfilter[1]
@ -115,12 +53,6 @@ OPTIONS
Display a list of available dlfilters. Use with option -v (must come
before option --list-dlfilters) to show long descriptions.
-a::
Force system-wide collection. Scripts run without a <command>
normally use -a by default, while scripts run with a <command>
normally don't - this option allows the latter to be run in
system-wide mode.
-i::
--input=::
Input file name. (default: perf.data unless stdin is a fifo)
@ -342,7 +274,6 @@ OPTIONS
Display extended information about the perf.data file. This adds
information which may be very large and thus may clutter the display.
It currently includes: cpu and numa topology of the host system.
It can only be used with the perf script report mode.
--show-kernel-path::
Try to resolve the path of [kernel.kallsyms]
@ -543,6 +474,5 @@ include::guest-files.txt[]
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-script-perl[1],
linkperf:perf-script-python[1], linkperf:perf-intel-pt[1],
linkperf:perf-dlfilter[1]
linkperf:perf-record[1], linkperf:perf-script-python[1],
linkperf:perf-intel-pt[1], linkperf:perf-dlfilter[1]

View File

@ -621,6 +621,16 @@ user/system lands:
Those times are the very same as displayed by the 'time' tool.
We also display a clock-based timing metric that depends on the
target being monitored:
83723.452481 task-clock (msec) # 1.004 CPUs utilized
For a single task, task-clock reports a clock count specific to that
task. When the target is a CPU or the whole system (-a or -C),
cpu-clock is reported instead. cpu-clock is a high-resolution per-CPU
timer. See perf_event_open(2) for more details.
CSV FORMAT
----------
@ -671,4 +681,4 @@ that can be used for parsing.
SEE ALSO
--------
linkperf:perf-top[1], linkperf:perf-list[1]
linkperf:perf-top[1], linkperf:perf-list[1], perf_event_open(2)

View File

@ -8,7 +8,7 @@ perf-test - Runs sanity tests.
SYNOPSIS
--------
[verse]
'perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]'
'perf test [<options>] [{list|requisites} [<test-name-fragment>]|[<test-name-fragments>|<test-numbers>]]'
DESCRIPTION
-----------
@ -18,9 +18,39 @@ also will look for a directory with more tests in the form of scripts.
To get a list of available tests use 'perf test list', specifying a test name
fragment will show all tests that have it.
To get a list of what the tests need, i.e. of their requisites (see below), use
'perf test requisites', that takes the same test name fragments and numbers as
'list'.
To run just specific tests, inform test name fragments or the numbers obtained
from 'perf test list'.
REQUISITES
----------
Shell tests run perf, that maps ring buffers, so they are taken to need room
in the per user budget set in kernel.perf_event_mlock_kb, shared by the tests
running at the same time, that take turns using it. Tests state what they
need, or waive, in a comma separated list in the parens ending their
description line, e.g.:
# perf stat tests (no_mlock)
Each requisite is named in that list, "mlock" being room in the budget set in
kernel.perf_event_mlock_kb, and takes a "no_" prefix to waive it: "(mlock)"
states the default, "(no_mlock)" waives it, for tests that don't map ring
buffers. Leaving a requisite out states nothing about it, so what happens
then is up to each kind of test: shell ones run perf, that maps ring buffers,
so they are taken to need room in the budget unless they waive it, while C
suites say which ones map, see DEFINE_SUITE_NEEDS_MLOCK() in tests.h.
"exclusive" is a catch-all: the test can't run alongside any other one, so
it runs alone, in sequence, and implies every other requisite; it can't be
waived. More requisites are to come, each stating what a test needs, till
the catch-all isn't needed anymore.
Use 'perf test requisites' to list what each test needs. That listing states
the needs, not the requisites form used in the scripts: a test listed as
needing "mlock" is one whose script doesn't say "(no_mlock)".
OPTIONS
-------
-s::
@ -36,8 +66,8 @@ OPTIONS
-S::
--sequential::
Run all tests one after the other. By default "exclusive"
tests are run sequentially, but other tests are run in
Run all tests one after the other. By default the tests asking to be
"exclusive" (see REQUISITES) run sequentially, but other tests run in
parallel to speed execution.
-r::

View File

@ -53,6 +53,14 @@ TIMECHART OPTIONS
-f::
--force::
Don't complain, do it.
--tui::
Rather than writing an SVG file, interactively display the timechart
in the terminal using the 'ttimechart' python script (see
linkperf:perf-script[1]). The script requires the perf python module
and the python 'textual' library. The CPU, task, I/O and summary views
can be zoomed ('+'/'-'), panned (shift+arrows) and the state of the
selected row at the cursor is described. The -i, -P, -T and -p options
are passed to the script, other output options are ignored.
--symfs=<directory[,layout]>::
Look for files with symbols relative to this directory. The optional
layout can be 'hierarchy' (default, matches full path) or 'flat'

View File

@ -25,6 +25,12 @@ OPTIONS
--count=<count>::
Event period to sample.
-W::
--weight::
Enable weighted sampling. One or more additional weights can be recorded per sample
and can be displayed with the weight, weight2, weight3 and local_weight sort keys.
Possible uses for weights are memory or instruction retirement latencies.
-C <cpu-list>::
--cpu=<cpu>::
Monitor only on the list of CPUs provided. Multiple CPUs can be provided as a
@ -43,6 +49,11 @@ Default is to monitor all CPUS.
encoding with the layout of the event control registers as described
by entries in /sys/bus/event_source/devices/cpu/format/*.
--hybrid-merge::
Merge matching events from all hybrid core PMUs into one
display. For example, if a wildcard expands to run on both p-cores and
e-cores, this aggregates them into a single view.
--filter=<filter>::
Event filter. This option should follow an event selector (-e). For
syntax see linkperf:perf-record[1].

View File

@ -172,6 +172,12 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
Trace system calls. This options is enabled by default, disable with
--no-syscalls.
--syscall-augment::
Augment system call arguments using BPF, the default when BPF support
is available. Disable with --no-syscall-augment to use the
raw_syscalls tracepoints instead, such as when more tasks are alive
at once than augmentation can trace.
--call-graph [mode,type,min[,limit],order[,key][,branch]]::
Setup and enable call-graph (stack chain/backtrace) recording.
See `--call-graph` section in perf-record and perf-report

View File

@ -478,6 +478,19 @@ The size of the cacheline in bytes. Format:
unsigned int cln_size;
HEADER_MEMORY_RANGES = 35,
List of memory ranges. The format of the data is as below.
u32 nr_memory_ranges;
struct memory_range {
u64 base;
u64 length;
int node;
u8 local_region_id;
u8 remote_region_id;
}; [nr_memory_ranges]
other bits are reserved and should be ignored for now
HEADER_FEAT_BITS = 256,

View File

@ -4,7 +4,6 @@ Compare performance results with: perf diff [<old file> <new file>]
Boolean options have negative forms, e.g.: perf report --no-children
To not accumulate CPU time of children symbols add --no-children
Customize output of perf script with: perf script -F event,ip,sym
Generate a script for your data: perf script -g <lang>
Save output of perf stat using: perf stat record <target workload>
Create an archive with symtabs to analyse on other machine: perf archive
Search options using a keyword: perf report -h <keyword>
@ -66,3 +65,5 @@ For latency profiling, try: perf record/report --latency
For parallelism histogram, try: perf report --hierarchy --sort latency,parallelism,comm,symbol
To analyze particular parallelism levels, try: perf report --latency --parallelism=32-64
To see how parallelism changes over time, try: perf report -F time,latency,parallelism --time-quantum=1s
When merging events like cycles, different core frequencies and instructions per cycle mean the counts may not fairly reflect time spent in a function.
Use --hybrid-merge to merge matching events from hybrid cores into one view

View File

@ -14,23 +14,29 @@
.SUFFIXES:
#
# We don't want to pass along options like -j:
# If no parallel build was requested, do a parallel build with multiple jobs,
# based on the number of CPUs online in this system: 'make -j8' on an 8-CPU
# system, etc.
#
unexport MAKEFLAGS
#
# Do a parallel build with multiple jobs, based on the number of CPUs online
# in this system: 'make -j8' on a 8-CPU system, etc.
# If MAKEFLAGS contains '-j' or 'jobserver', JOBS is intentionally left
# uninitialized so the native GNU Make jobserver can seamlessly control the
# parallel bounds of the build.
#
# (To override it, run 'make JOBS=1' and similar.)
#
ifeq ($(JOBS),)
JOBS := $(shell (getconf _NPROCESSORS_ONLN || grep -E -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
ifeq ($(JOBS),0)
JOBS := 1
ifeq ($(findstring -j,$(MAKEFLAGS)),)
ifeq ($(findstring jobserver,$(MAKEFLAGS)),)
ifeq ($(JOBS),)
JOBS := $(shell (getconf _NPROCESSORS_ONLN || grep -E -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
ifeq ($(JOBS),0)
JOBS := 1
endif
endif
PARALLEL_OPT := -j$(JOBS)
endif
endif
#
# Only pass canonical directory names as the output directory:
#
@ -58,11 +64,11 @@ else
endif
define print_msg
@printf ' BUILD: Doing '\''make \033[33m-j'$(JOBS)'\033[m'\'' $(BUILD_TYPE) build\n'
@printf ' BUILD: Doing '\''make\033[33m%s\033[m'\'' $(BUILD_TYPE) build\n' "$(if $(JOBS), -j$(JOBS),)"
endef
define make
@$(MAKE) -f Makefile.perf --no-print-directory -j$(JOBS) O=$(FULL_O) $(SET_DEBUG) $@
@$(MAKE) -f Makefile.perf --no-print-directory $(PARALLEL_OPT) O=$(FULL_O) $(SET_DEBUG) $@
endef
#
@ -87,6 +93,20 @@ ifeq ($(has_clean),1)
$(rest): clean
endif # rest
endif # has_clean
ifneq ($(filter install-build-deps,$(MAKECMDGOALS)),)
after_deps := $(filter-out clean install-build-deps,$(MAKECMDGOALS))
ifneq ($(after_deps),)
$(after_deps): install-build-deps
endif
endif
ifneq ($(filter all,$(MAKECMDGOALS)),)
install_goals := $(filter-out install-build-deps,$(filter install%,$(MAKECMDGOALS)))
ifneq ($(install_goals),)
$(install_goals): all
endif
endif
endif # MAKECMDGOALS
#
@ -106,7 +126,10 @@ clean:
# make -C tools/perf -f tests/make
#
build-test:
@$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory tarpkg make_static make_with_gtk2 out
@$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory tarpkg
@$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory make_static
@$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory make_with_gtk4
@$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory out
build-test-tarball:
@$(MAKE) -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory out
@ -114,6 +137,9 @@ build-test-tarball:
check-headers:
@./check-headers.sh
sync-headers:
@./scripts/sync-headers.sh $(SYNC_HEADERS_ARGS)
#
# All other targets get passed through:
#
@ -121,4 +147,4 @@ check-headers:
$(print_msg)
$(make)
.PHONY: tags TAGS FORCE Makefile build-test build-test-tarball check-headers
.PHONY: all clean tags TAGS FORCE Makefile build-test build-test-tarball check-headers sync-headers

View File

@ -38,7 +38,7 @@ ifeq ($(CC_NO_CLANG), 0)
# Default to host architecture if ARCH is not explicitly given.
ifeq ($(ARCH), $(HOSTARCH))
CLANG_TARGET_FLAGS := $(shell $(CLANG) -print-target-triple)
CLANG_TARGET_FLAGS := $(shell $(CC) -print-target-triple)
else
CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(ARCH))
endif
@ -53,8 +53,15 @@ ifeq ($(CC_NO_CLANG), 0)
CLANG_FLAGS += --target=$(notdir $(CROSS_COMPILE:%-=%))
endif # CROSS_COMPILE
CC := $(CLANG) $(CLANG_FLAGS) -fintegrated-as
CXX := $(CXX) $(CLANG_FLAGS) -fintegrated-as
CC := $(CC) $(CLANG_FLAGS) -fintegrated-as
# CC being clang says nothing about CXX: "make LLVM=1" overrides both, but
# "make CC=clang" leaves CXX as g++. Probe CXX the way Makefile.include
# probes CC rather than assuming the two match.
CXX_NO_CLANG := $(shell if command -v $(firstword $(CXX)) >/dev/null 2>&1; then $(CXX) -dM -E -x c++ /dev/null; fi | grep -Fq "__clang__"; echo $$?)
ifeq ($(CXX_NO_CLANG), 0)
CXX := $(CXX) $(CLANG_FLAGS) -fintegrated-as
endif
# Enabled Wthread-safety analysis for clang builds.
CFLAGS += -Wthread-safety
@ -305,7 +312,7 @@ PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
# Python 3.8 changed the output of `python-config --ldflags` to not include the
# '-lpythonX.Y' flag unless '--embed' is also passed. The feature check for
# libpython fails if that flag is not included in LDFLAGS
# python-module fails if that flag is not included in LDFLAGS
ifeq ($(shell $(PYTHON_CONFIG_SQ) --ldflags --embed 2>&1 1>/dev/null; echo $$?), 0)
PYTHON_CONFIG_LDFLAGS := --ldflags --embed
else
@ -328,8 +335,8 @@ ifdef PYTHON_CONFIG
endif
endif
FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
FEATURE_CHECK_CFLAGS-python-module := $(PYTHON_EMBED_CCOPTS)
FEATURE_CHECK_LDFLAGS-python-module := $(PYTHON_EMBED_LDOPTS)
FEATURE_CHECK_LDFLAGS-libaio = -lrt
@ -410,6 +417,10 @@ ifeq ($(feature-pthread-barrier), 1)
CFLAGS += -DHAVE_PTHREAD_BARRIER
endif
ifeq ($(feature-pthread-mutex-robust), 1)
CFLAGS += -DHAVE_PTHREAD_MUTEX_ROBUST
endif
ifndef NO_BIONIC
$(call feature_check,bionic)
ifeq ($(feature-bionic), 1)
@ -470,7 +481,7 @@ else
else
ifneq ($(feature-libdw), 1)
ifndef NO_LIBDW
$(warning No libdw.h found or old libdw.h found or elfutils is older than 0.157, disables dwarf support. Please install new elfutils-devel/libdw-dev)
$(warning No libdw.h found or old libdw.h found or elfutils is older than 0.160, disables dwarf support. Please install new elfutils-devel/libdw-dev)
NO_LIBDW := 1
endif
endif # Dwarf support
@ -774,42 +785,22 @@ ifndef NO_SLANG
endif
endif
ifdef GTK2
FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
$(call feature_check,gtk2)
ifneq ($(feature-gtk2), 1)
$(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev)
NO_GTK2 := 1
ifdef GTK4
FLAGS_GTK4=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk4 2>/dev/null)
$(call feature_check,gtk4)
ifneq ($(feature-gtk4), 1)
$(warning GTK4 not found, disables GTK4 support. Please install gtk4-devel or libgtk-4-dev)
override GTK4 :=
else
$(call feature_check,gtk2-infobar)
ifeq ($(feature-gtk2-infobar), 1)
GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
endif
CFLAGS += -DHAVE_GTK2_SUPPORT
GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null)
GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null)
CFLAGS += -DHAVE_GTK4_SUPPORT
GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk4 2>/dev/null)
GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk4 2>/dev/null)
EXTLIBS += -ldl
endif
endif
ifdef LIBPERL
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS = $(shell perl -MExtUtils::Embed -e ccopts 2>/dev/null)
PERL_EMBED_CCOPTS := $(filter-out -specs=%,$(PERL_EMBED_CCOPTS))
PERL_EMBED_CCOPTS := $(filter-out -flto% -ffat-lto-objects, $(PERL_EMBED_CCOPTS))
PERL_EMBED_LDOPTS := $(filter-out -specs=%,$(PERL_EMBED_LDOPTS))
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
$(call feature_check,libperl)
ifneq ($(feature-libperl), 1)
$(error Missing perl devel files. Please install perl-ExtUtils-Embed/libperl-dev)
else
LDFLAGS += $(PERL_EMBED_LDFLAGS)
EXTLIBS += $(PERL_EMBED_LIBADD)
CFLAGS += -DHAVE_LIBPERL_SUPPORT
$(call detected,CONFIG_LIBPERL)
# libperf-gtk.so is dlopen()ed at runtime and calls back into
# symbols defined in the perf binary itself (callchain_param,
# symbol_conf, evsel__name, ...): perf needs to export those
# dynamically for the plugin to resolve them.
LDFLAGS += -rdynamic
endif
endif
@ -821,13 +812,22 @@ endif
disable-python = $(eval $(disable-python_code))
define disable-python_code
CFLAGS += -DNO_LIBPYTHON
$(warning $1)
NO_LIBPYTHON := 1
NO_PYTHON_MODULE := 1
endef
# Minimum Python version for the interpreters perf runs while building,
# the same one the kernel requires, see
# Documentation/process/changes.rst: jevents generation (pmu-events/
# jevents.py) and the python binding (util/setup.py) both use PEP 585
# generics, list[...] and friends, that are subscriptable only from
# Python 3.9.
ifdef PYTHON
PYTHON_39_GOOD := $(shell $(PYTHON) -c 'import sys;print("1" if sys.version_info >= (3, 9) else "0")' 2> /dev/null)
endif
PYTHON_EXTENSION_SUFFIX := '.so'
ifdef NO_LIBPYTHON
ifdef NO_PYTHON_MODULE
$(call disable-python,Python support disabled by user)
else
@ -840,11 +840,18 @@ else
$(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev)
else
ifneq ($(feature-libpython), 1)
ifneq ($(feature-python-module), 1)
$(call disable-python,No 'Python.h' was found: disables Python support - please install python-devel/python-dev)
else
LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
EXTLIBS += $(PYTHON_EMBED_LIBADD)
# The binding is built even when jevents generation is turned off
# with NO_JEVENTS=1, which skips the check in that block below, so
# check the version here as well: otherwise util/setup.py dies on
# older interpreters with "TypeError: 'type' object is not
# subscriptable" instead of a Makefile error.
ifneq ($(PYTHON_39_GOOD), 1)
$(error ERROR: Python interpreter needed for the python binding too old (older than 3.9). Install a newer python or build with NO_PYTHON_MODULE=1.)
endif
CFLAGS += -DHAVE_PYTHON_MODULE_SUPPORT
PYTHON_SETUPTOOLS_INSTALLED := $(shell $(PYTHON) -c 'import setuptools;' 2> /dev/null && echo "yes" || echo "no")
ifeq ($(PYTHON_SETUPTOOLS_INSTALLED), yes)
PYTHON_EXTENSION_SUFFIX := $(shell $(PYTHON) -c 'from importlib import machinery; print(machinery.EXTENSION_SUFFIXES[0])')
@ -855,8 +862,6 @@ else
else
$(warning Missing python setuptools, the python binding won't be built, please install python3-setuptools or equivalent)
endif
CFLAGS += -DHAVE_LIBPYTHON_SUPPORT
$(call detected,CONFIG_LIBPYTHON)
ifeq ($(filter -fPIC,$(CFLAGS)),)
# Building a shared library requires position independent code.
CFLAGS += -fPIC
@ -877,10 +882,8 @@ ifneq ($(NO_JEVENTS),1)
ifndef PYTHON
$(error ERROR: No python interpreter needed for jevents generation. Install python or build with NO_JEVENTS=1.)
else
# jevents.py uses f-strings present in Python 3.6 released in Dec. 2016.
JEVENTS_PYTHON_GOOD := $(shell $(PYTHON) -c 'import sys;print("1" if(sys.version_info.major >= 3 and sys.version_info.minor >= 6) else "0")' 2> /dev/null)
ifneq ($(JEVENTS_PYTHON_GOOD), 1)
$(error ERROR: Python interpreter needed for jevents generation too old (older than 3.6). Install a newer python or build with NO_JEVENTS=1.)
ifneq ($(PYTHON_39_GOOD), 1)
$(error ERROR: Python interpreter needed for jevents generation too old (older than 3.9). Install a newer python or build with NO_JEVENTS=1.)
endif
endif
endif
@ -1297,7 +1300,6 @@ $(call detected_var,tipdir_SQ)
$(call detected_var,srcdir_SQ)
$(call detected_var,LIBDIR)
$(call detected_var,GTK_CFLAGS)
$(call detected_var,PERL_EMBED_CCOPTS)
$(call detected_var,PYTHON_EMBED_CCOPTS)
ifneq ($(BISON_FILE_PREFIX_MAP),)
$(call detected_var,BISON_FILE_PREFIX_MAP)

View File

@ -17,9 +17,8 @@ include ../scripts/utilities.mak
#
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
#
# Define LIBPERL to enable perl script extension.
#
# Define NO_LIBPYTHON to disable python script extension.
# Define NO_PYTHON_MODULE to disable python script extension.
#
# Define PYTHON to point to the python binary if the default
# `python' is not correct; for example: PYTHON=python2
@ -49,7 +48,7 @@ include ../scripts/utilities.mak
#
# Define NO_SLANG if you do not want TUI support.
#
# Define GTK2 if you want GTK+ GUI support.
# Define GTK4 if you want GTK+ GUI support.
#
# Define NO_DEMANGLE if you do not want C++ symbol demangling.
#
@ -64,9 +63,6 @@ include ../scripts/utilities.mak
#
# Define NO_LIBBIONIC if you do not want bionic support
#
# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
# for dwarf backtrace post unwind.
#
# Define NO_LIBTRACEEVENT=1 if you don't want libtraceevent to be linked,
# this will remove multiple features and tools, such as 'perf trace',
# that need it to read tracefs event format files, etc.
@ -129,6 +125,10 @@ include ../scripts/utilities.mak
# Define GEN_VMLINUX_H to generate vmlinux.h from the BTF.
#
# Define NO_SHELLCHECK if you do not want to run shellcheck during build
#
# Define NO_MYPY if you do not want to run mypy during build
#
# Define NO_PYLINT if you do not want to run pylint during build
# As per kernel Makefile, avoid funny character set dependencies
unexport LC_ALL
@ -258,18 +258,67 @@ ifneq ($(SHELLCHECK),)
sed -e 's/.\+ \([0-9]\+\).\([0-9]\+\).\([0-9]\+\)/\1\2\3/g') \< 072), 1)
SHELLCHECK :=
else
SHELLCHECK := $(SHELLCHECK) -s bash -a -S warning
SHELLCHECK := $(SHELLCHECK) -s bash -a -S warning -x -P SCRIPTDIR
endif
endif
# Runs mypy on perf python files
ifeq ($(MYPY),1)
MYPY := $(shell which mypy 2> /dev/null)
# Runs mypy on perf python files.
# Wait until after the fixdep bootstrap sub-make (force_fixdep != 1) so
# command-line overrides (MYPY=1, MYPY=/custom/path, NO_MYPY=1) reach the
# main Makefile.perf pass intact, then strip MYPY=% from MAKEOVERRIDES
# (substituting escaped spaces so multi-word overrides like MYPY="mypy --strict"
# are removed as a single token) so child Makefile.build sub-makes inherit the
# MYPYPATH-wrapped export MYPY environment variable.
ifneq ($(force_fixdep),1)
MAKEOVERRIDES := $(subst __SPACE__,\ ,$(filter-out MYPY=%,$(subst \ ,__SPACE__,$(MAKEOVERRIDES))))
ifeq ($(NO_MYPY),1)
override MYPY :=
else ifeq ($(filter-out 1,$(MYPY)),)
override MYPY := $(shell which mypy 2> /dev/null)
endif
ifneq ($(MYPY),)
override MYPY := MYPYPATH=$(srctree)/tools/perf/python $(MYPY) --ignore-missing-imports
endif
endif
# Runs pylint on perf python files
ifeq ($(PYLINT),1)
PYLINT := $(shell which pylint 2> /dev/null)
# Runs pylint on perf python files.
# Require pylint >= 2.16.0 (which introduced W0718 broad-exception-caught).
# Note: astroid's ImportlibFinder only resolves .pyi stubs for package
# directories (__init__.pyi), not single-file stubs like perf.pyi, and does not
# introspect C extensions by default. Pass 'perf' in --ignored-modules (leaving
# perf module type-checking to mypy via perf.pyi) so pylint does not depend on
# building the perf Python C extension first.
# Disabled warnings:
# W0123 (eval-used): Use of eval()
# W0311 (bad-indentation): Non-4-space indentation
# W0511 (fixme): Presence of FIXME/TODO comments
# W0603 (global-statement): Use of the global statement
# W0622 (redefined-builtin): Redefining a built-in name (e.g. id, type, dir)
# W0718 (broad-exception-caught): Catching broad Exception
# Wait until after the fixdep bootstrap sub-make (force_fixdep != 1) before
# resolving PYLINT and stripping PYLINT=% from MAKEOVERRIDES (substituting
# escaped spaces so multi-word overrides are removed as a single token) so child
# Makefile.build sub-makes inherit the PYTHONPATH- and flag-wrapped export.
ifneq ($(force_fixdep),1)
MAKEOVERRIDES := $(subst __SPACE__,\ ,$(filter-out PYLINT=%,$(subst \ ,__SPACE__,$(MAKEOVERRIDES))))
ifeq ($(NO_PYLINT),1)
override PYLINT :=
else ifeq ($(filter-out 1,$(PYLINT)),)
override PYLINT := $(shell which pylint 2> /dev/null)
endif
ifneq ($(PYLINT),)
ifneq ($(shell $(PYLINT) --version 2>/dev/null | \
awk '/^pylint / { split($$2, v, "."); print (v[1]+0 > 2 || (v[1]+0 == 2 && v[2]+0 >= 16)) }'), 1)
$(warning Warning: pylint version is older than 2.16.0, skipping pylint checks.)
override PYLINT :=
else
override PYLINT := PYTHONPATH=$(srctree)/tools/perf/python:$(srctree)/tools/perf/pmu-events \
$(PYLINT) --disable=all --enable=E,W --disable=W0123,W0311,W0511,W0603,W0622,W0718 \
--ignored-modules=perf,textual,setproctitle
endif
endif
endif
export srctree OUTPUT RM CC CXX RUSTC CLANG LD AR CFLAGS CXXFLAGS RUST_FLAGS V BISON FLEX AWK LIBBPF READELF
@ -278,9 +327,17 @@ export HOSTCC HOSTLD HOSTAR HOSTCFLAGS SHELLCHECK MYPY PYLINT CONFIG_PERF_BPF_SK
include $(srctree)/tools/build/Makefile.include
ifeq ($(force_fixdep),1)
goals := $(filter-out all sub-make, $(MAKECMDGOALS))
goals := $(filter-out all sub-make clean, $(MAKECMDGOALS))
$(goals) all: sub-make
ifneq ($(filter clean,$(MAKECMDGOALS)),)
clean-make:
$(Q)$(MAKE) -f Makefile.perf -j1 clean
fixdep: clean-make
.PHONY: clean-make
endif
$(goals) all clean: sub-make
sub-make: fixdep
$(Q)$(MAKE) FIXDEP_BUILT=1 -f Makefile.perf $(goals)
@ -397,7 +454,8 @@ PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf*.so
# Put Python bytecode in output directory
export PYTHONPYCACHEPREFIX := $(OUTPUT)/__pycache__
ifneq ($(quiet),)
python_setup_quiet=--quiet
@ -437,11 +495,6 @@ OTHER_PROGRAMS = $(OUTPUT)perf
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
endif
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
export PERL_PATH
LIBPERF_BENCH_IN := $(OUTPUT)perf-bench-in.o
LIBPERF_BENCH := $(OUTPUT)libperf-bench.a
@ -473,7 +526,7 @@ ifneq ($(OUTPUT),)
CFLAGS += -I$(OUTPUT)
endif
ifdef GTK2
ifdef GTK4
ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so
GTK_IN := $(OUTPUT)gtk-in.o
endif
@ -485,8 +538,8 @@ endif
EXTLIBS := $(call filter-out,$(EXCLUDE_EXTLIBS),$(EXTLIBS))
LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
PERFLIBS_PY := $(call filter-out,$(LIBPERF_BENCH) $(LIBPERF_TEST),$(PERFLIBS))
LIBS_PY = -Wl,--whole-archive $(PERFLIBS_PY) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
PERFLIBS_PY := $(call filter-out,$(LIBPERF_BENCH) $(LIBPERF_TEST),$(PERFLIBS)) $(EXTRA_PERFLIBS)
LIBS_PY = -Wl,--whole-archive $(PERFLIBS_PY) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
export INSTALL SHELL_PATH
@ -518,8 +571,10 @@ $(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python')
$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX): util/python.c util/setup.py python/perf.pyi $(PERFLIBS_PY)
$(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \
CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBS_PY)' \
PYTHON_EXT_DEPS='$(PERFLIBS_PY)' \
$(PYTHON_WORD) util/setup.py \
$(python_setup_quiet) build_ext; \
$(MKDIR) -p $(OUTPUT)python; \
cp $(PYTHON_EXTBUILD_LIB)perf*.so $(OUTPUT)python/; \
if [ "$(abspath python/perf.pyi)" != "$(abspath $(OUTPUT)python/perf.pyi)" ]; then \
cp python/perf.pyi $(OUTPUT)python/; \
@ -537,6 +592,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
PERF_IN := $(OUTPUT)perf-in.o
export NO_JEVENTS
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
@ -592,6 +648,54 @@ $(SCRIPTS) : $(OUTPUT)% : %.sh
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
$(Q)$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
ifdef SHELLCHECK
# Run shellcheck independently of C builds.
all: shellcheck-perf shellcheck-tests
.PHONY: shellcheck-perf shellcheck-tests
shellcheck-perf:
$(Q)$(MAKE) $(build)=perf shellcheck
shellcheck-tests:
$(Q)$(MAKE) $(build)=perf-test dir=tests shellcheck
endif
ifdef MYPY
# Run mypy independently of C builds.
all: mypy-perf mypy-tests mypy-util mypy-pmu-events
.PHONY: mypy-perf mypy-tests mypy-util mypy-pmu-events
mypy-perf:
$(Q)$(MAKE) $(build)=perf mypy
mypy-tests:
$(Q)$(MAKE) $(build)=perf-test dir=tests mypy
mypy-util:
$(Q)$(MAKE) $(build)=perf-util dir=util mypy
mypy-pmu-events:
$(Q)$(MAKE) $(build)=pmu-events dir=pmu-events mypy
endif
ifdef PYLINT
# Run pylint independently of C builds.
all: pylint-perf pylint-tests pylint-util pylint-pmu-events
.PHONY: pylint-perf pylint-tests pylint-util pylint-pmu-events
pylint-perf:
$(Q)$(MAKE) $(build)=perf pylint
pylint-tests:
$(Q)$(MAKE) $(build)=perf-test dir=tests pylint
pylint-util:
$(Q)$(MAKE) $(build)=perf-util dir=util pylint
pylint-pmu-events:
$(Q)$(MAKE) $(build)=pmu-events dir=pmu-events pylint
endif
# These can record PERF_VERSION
perf.spec $(SCRIPTS) \
: $(OUTPUT)PERF-VERSION-FILE
@ -766,6 +870,9 @@ help:
@echo ''
@echo 'Perf maintainer targets:'
@echo ' clean - clean all binary objects and build output'
@echo ' check-headers - check which header copies are out of sync with the kernel'
@echo ' sync-headers - sync those header copies with the kernel, creating commits'
@echo ' (SYNC_HEADERS_ARGS="..." passes options to the script)'
DOC_TARGETS := doc man html info pdf
@ -811,7 +918,7 @@ check: prepare
### Installation rules
ifdef GTK2
ifdef GTK4
install-gtk: $(OUTPUT)libperf-gtk.so
$(call QUIET_INSTALL, 'GTK UI') \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \
@ -846,21 +953,14 @@ endif
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
$(call QUIET_INSTALL, perf-iostat) \
$(INSTALL) $(OUTPUT)perf-iostat -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
ifdef LIBPERL
$(call QUIET_INSTALL, perl-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/perl/*.pl -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
endif
ifndef NO_LIBPYTHON
ifndef NO_PYTHON_MODULE
$(call QUIET_INSTALL, python-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/python/*.py -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python' && \
$(INSTALL) python/*.py -m 755 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python' && \
$(INSTALL) python/perf.pyi -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python' && \
if [ -f "$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX)" ]; then \
$(INSTALL) "$(OUTPUT)python/perf$(PYTHON_EXTENSION_SUFFIX)" -m 644 -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/python'; \
fi
endif
$(call QUIET_INSTALL, dlfilters) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/dlfilters'; \
@ -907,8 +1007,10 @@ install: install-bin try-install-man
install-build-deps:
$(Q)$(SHELL) $(srctree)/tools/perf/scripts/install-build-deps.sh $(INSTALL_BUILD_DEPS_ARGS)
install-python_ext:
$(PYTHON_WORD) util/setup.py $(python_setup_quiet) install --root='/$(DESTDIR_SQ)'
install-python_ext: $(LANG_BINDINGS)
$(PYTHON_WORD) util/setup.py $(python_setup_quiet) \
$(if $(OUTPUT),egg_info --egg-base $(OUTPUT)) \
install --root='/$(DESTDIR_SQ)'
# 'make install-doc' should call 'make -C Documentation install'
$(INSTALL_DOC_TARGETS):
@ -917,7 +1019,12 @@ $(INSTALL_DOC_TARGETS):
### Cleaning rules
python-clean:
$(python-clean)
$(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)__pycache__ \
$(OUTPUT)python/perf*.so
@if [ "$(abspath python/perf.pyi)" != "$(abspath $(OUTPUT)python/perf.pyi)" ]; \
then \
$(RM) $(OUTPUT)python/perf.pyi; \
fi
$(LIBAPI_OUTPUT) $(LIBBPF_OUTPUT) $(LIBPERF_OUTPUT) $(LIBSUBCMD_OUTPUT) $(LIBSYMBOL_OUTPUT):
$(Q)$(MKDIR) -p $@
@ -948,10 +1055,11 @@ clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(
$(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive \
$(OUTPUT)perf-iostat $(LANG_BINDINGS)
$(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '*.a' -delete -o \
-name '\.*.cmd' -delete -o -name '\.*.d' -delete -o -name '*.shellcheck_log' -delete
-name '\.*.cmd' -delete -o -name '\.*.d' -delete -o -name '*.shellcheck_log' -delete -o \
-name '*.mypy_log' -delete -o -name '*.pylint_log' -delete
$(Q)$(RM) $(OUTPUT).config-detected
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 \
perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so
perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so $(OUTPUT)libperf-gtk.so
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo \
TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE \
$(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
@ -975,7 +1083,9 @@ endif
FORCE:
.PHONY: all install install-build-deps clean config-clean strip install-gtk
.PHONY: all install install-bin install-tools install-tests install-build-deps
.PHONY: install-gtk install-python_ext $(DOC_TARGETS) $(INSTALL_DOC_TARGETS)
.PHONY: clean config-clean strip
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope FORCE prepare bpf-skel-prepare
.PHONY: python_perf_target

View File

@ -34,6 +34,7 @@ static int sample_ustack(struct perf_sample *sample,
}
stack_size = map__end(map) - sp;
map__put(map);
stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
memcpy(buf, (void *) sp, stack_size);

View File

@ -34,6 +34,7 @@ static int sample_ustack(struct perf_sample *sample,
}
stack_size = map__end(map) - sp;
map__put(map);
stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
memcpy(buf, (void *) sp, stack_size);

View File

@ -26,7 +26,7 @@
static char *_get_field(const char *line)
{
char *line2, *nl;
const char *line2, *nl;
line2 = strrchr(line, ' ');
if (!line2)

View File

@ -34,6 +34,7 @@ static int sample_ustack(struct perf_sample *sample,
}
stack_size = map__end(map) - sp;
map__put(map);
stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
memcpy(buf, (void *) sp, stack_size);

View File

@ -152,9 +152,10 @@ static int check_return_addr(struct dso *dso, Dwarf_Addr mapped_pc)
Dwarf_Addr end = mapped_pc;
bool signalp;
mutex_lock(dso__lock(dso));
dwfl = dso__libdw_dwfl(dso);
if (!dwfl)
return -1;
goto out;
mod = dwfl_addrmodule(dwfl, mapped_pc);
if (!mod) {
@ -183,6 +184,7 @@ static int check_return_addr(struct dso *dso, Dwarf_Addr mapped_pc)
rc = check_return_reg(ra_regno, frame);
out:
mutex_unlock(dso__lock(dso));
return rc;
}

View File

@ -1 +1,2 @@
perf-util-y += util/
perf-test-y += tests/

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef ARCH_TESTS_H
#define ARCH_TESTS_H
struct test_suite;
extern struct test_suite *arch_tests[];
#endif

View File

@ -8,6 +8,8 @@
#include <linux/types.h>
#include "../../../../arch/riscv/include/uapi/asm/perf_regs.h"
void perf_regs_load(u64 *regs);
#define PERF_REGS_MASK ((1ULL << PERF_REG_RISCV_MAX) - 1)
#define PERF_REGS_MAX PERF_REG_RISCV_MAX

View File

@ -0,0 +1,4 @@
perf-test-y += regs_load.o
perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
perf-test-y += arch-tests.o

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
#include "tests/tests.h"
#include "arch-tests.h"
struct test_suite *arch_tests[] = {
#ifdef HAVE_DWARF_UNWIND_SUPPORT
&suite__dwarf_unwind,
#endif
NULL,
};

View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0
#include <string.h>
#include "perf_regs.h"
#include "thread.h"
#include "map.h"
#include "maps.h"
#include "event.h"
#include "debug.h"
#include "tests/tests.h"
#define STACK_SIZE 8192
static int sample_ustack(struct perf_sample *sample,
struct thread *thread, u64 *regs)
{
struct stack_dump *stack = &sample->user_stack;
struct map *map;
unsigned long sp;
u64 stack_size, *buf;
buf = malloc(STACK_SIZE);
if (!buf) {
pr_debug("failed to allocate sample uregs data\n");
return -1;
}
sp = (unsigned long) regs[PERF_REG_RISCV_SP];
map = maps__find(thread__maps(thread), (u64)sp);
if (!map) {
pr_debug("failed to get stack map\n");
free(buf);
return -1;
}
stack_size = map__end(map) - sp;
map__put(map);
stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
memcpy(buf, (void *) sp, stack_size);
stack->data = (char *) buf;
stack->size = stack_size;
return 0;
}
int test__arch_unwind_sample(struct perf_sample *sample,
struct thread *thread)
{
struct regs_dump *regs = perf_sample__user_regs(sample);
u64 *buf;
buf = calloc(PERF_REGS_MAX, sizeof(u64));
if (!buf) {
pr_debug("failed to allocate sample uregs data\n");
return -1;
}
perf_regs_load(buf);
regs->abi = PERF_SAMPLE_REGS_ABI;
regs->regs = buf;
regs->mask = PERF_REGS_MASK;
return sample_ustack(sample, thread, buf);
}

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
/*
* Fill the u64 array 'regs' at the slots of enum perf_event_riscv_regs:
* x1..x31 map one-to-one onto PERF_REG_RISCV_RA..PERF_REG_RISCV_T6, and the
* stride stays 8 bytes on RV32 because the slots are u64 and the caller
* zeroes them.
*
* PERF_REG_RISCV_PC is filled with ra, the return address of the call to
* this function, so that unwinding starts at the caller rather than here.
*/
#if __riscv_xlen == 64
#define REG_S sd
#else
#define REG_S sw
#endif
#define STR_REG(r) REG_S x##r, 8 * r(a0)
.text
.type perf_regs_load,%function
SYM_FUNC_START(perf_regs_load)
STR_REG(1)
STR_REG(2)
STR_REG(3)
STR_REG(4)
STR_REG(5)
STR_REG(6)
STR_REG(7)
STR_REG(8)
STR_REG(9)
STR_REG(10)
STR_REG(11)
STR_REG(12)
STR_REG(13)
STR_REG(14)
STR_REG(15)
STR_REG(16)
STR_REG(17)
STR_REG(18)
STR_REG(19)
STR_REG(20)
STR_REG(21)
STR_REG(22)
STR_REG(23)
STR_REG(24)
STR_REG(25)
STR_REG(26)
STR_REG(27)
STR_REG(28)
STR_REG(29)
STR_REG(30)
STR_REG(31)
REG_S ra, 0(a0)
ret
SYM_FUNC_END(perf_regs_load)

View File

@ -8,6 +8,10 @@
#include "debug.h"
#include "tests/tests.h"
#if defined(MEMORY_SANITIZER) && !defined(__msan_unpoison)
# include <sanitizer/msan_interface.h>
#endif
#define STACK_SIZE 8192
static int sample_ustack(struct perf_sample *sample,

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "arch-tests.h"
#include "../util/topdown.h"
#include "debug.h"
@ -229,10 +231,38 @@ static int test__x86_topdown_slots_injection(struct test_suite *test __maybe_unu
return TEST_OK;
}
/*
* An explicit "slots,metrics_clear=1" event is still the slots event and
* must not cause an extra slots event to be injected into the group.
*/
static int test__x86_topdown_metrics_clear(struct test_suite *test __maybe_unused,
int subtest __maybe_unused)
{
struct perf_pmu *pmu;
char event_str[128];
int ret;
if (!topdown_sys_has_perf_metrics())
return TEST_OK;
pmu = perf_pmus__find_by_type(PERF_TYPE_RAW);
if (!pmu || !perf_pmu__has_format(pmu, "metrics_clear"))
return TEST_OK;
snprintf(event_str, sizeof(event_str),
"{%s/slots,metrics_clear=1/,%s/topdown-retiring/}",
pmu->name, pmu->name);
ret = test_sort(event_str, 2, 1);
TEST_ASSERT_EQUAL("explicit metrics_clear slots event isn't duplicated", ret, TEST_OK);
return TEST_OK;
}
static struct test_case x86_topdown_tests[] = {
TEST_CASE("topdown events", x86_topdown),
TEST_CASE("topdown sorting", x86_topdown_sorting),
TEST_CASE("topdown slots injection", x86_topdown_slots_injection),
TEST_CASE("topdown metrics_clear no extra slots", x86_topdown_metrics_clear),
{ .name = NULL, }
};

View File

@ -21,14 +21,31 @@ struct perf_mem_event perf_mem_events_intel_aux[PERF_MEM_EVENTS__MAX] = {
E(NULL, NULL, NULL, false, 0),
};
/*
* IBS events with exclude_{user,kernel} bits are rejected on hardware
* without the privilege filter unless swfilt is used: the extra tables
* carry the term, selected when the PMU exposes it.
*/
struct perf_mem_event perf_mem_events_amd[PERF_MEM_EVENTS__MAX] = {
E(NULL, NULL, NULL, false, 0),
E(NULL, NULL, NULL, false, 0),
E("mem-ldst", "%s//", NULL, false, 0),
};
struct perf_mem_event perf_mem_events_amd_swfilt[PERF_MEM_EVENTS__MAX] = {
E(NULL, NULL, NULL, false, 0),
E(NULL, NULL, NULL, false, 0),
E("mem-ldst", "%s/swfilt=1/", NULL, false, 0),
};
struct perf_mem_event perf_mem_events_amd_ldlat[PERF_MEM_EVENTS__MAX] = {
E(NULL, NULL, NULL, false, 0),
E(NULL, NULL, NULL, false, 0),
E("mem-ldst", "%s/ldlat=%u/", NULL, true, 0),
};
struct perf_mem_event perf_mem_events_amd_ldlat_swfilt[PERF_MEM_EVENTS__MAX] = {
E(NULL, NULL, NULL, false, 0),
E(NULL, NULL, NULL, false, 0),
E("mem-ldst", "%s/ldlat=%u,swfilt=1/", NULL, true, 0),
};

View File

@ -6,6 +6,8 @@ extern struct perf_mem_event perf_mem_events_intel[PERF_MEM_EVENTS__MAX];
extern struct perf_mem_event perf_mem_events_intel_aux[PERF_MEM_EVENTS__MAX];
extern struct perf_mem_event perf_mem_events_amd[PERF_MEM_EVENTS__MAX];
extern struct perf_mem_event perf_mem_events_amd_swfilt[PERF_MEM_EVENTS__MAX];
extern struct perf_mem_event perf_mem_events_amd_ldlat[PERF_MEM_EVENTS__MAX];
extern struct perf_mem_event perf_mem_events_amd_ldlat_swfilt[PERF_MEM_EVENTS__MAX];
#endif /* _X86_MEM_EVENTS_H */

View File

@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
@ -22,20 +23,35 @@
#include "util/env.h"
#include "util/header.h"
static bool x86__is_intel_graniterapids(void)
#define GENUINE_INTEL_SPR "GenuineIntel-6-8F"
#define GENUINE_INTEL_EMR "GenuineIntel-6-CF"
#define GENUINE_INTEL_GNR "GenuineIntel-6-A[DE]"
static bool cached_snc_supported;
static pthread_once_t snc_support_once = PTHREAD_ONCE_INIT;
static void init_snc_support(void)
{
static bool checked_if_graniterapids;
static bool is_graniterapids;
/* Sapphirerapids Emeraldrapids Graniterapids support SNC configuration. */
static const char *const supported_cpuids[] = {
GENUINE_INTEL_SPR, /* Sapphirerapids */
GENUINE_INTEL_EMR, /* Emeraldrapids */
GENUINE_INTEL_GNR, /* Graniterapids */
};
char *cpuid = get_cpuid_str((struct perf_cpu){0});
if (!checked_if_graniterapids) {
const char *graniterapids_cpuid = "GenuineIntel-6-A[DE]";
char *cpuid = get_cpuid_str((struct perf_cpu){0});
is_graniterapids = cpuid && strcmp_cpuid_str(graniterapids_cpuid, cpuid) == 0;
free(cpuid);
checked_if_graniterapids = true;
for (size_t i = 0; i < ARRAY_SIZE(supported_cpuids); i++) {
cached_snc_supported = cpuid && strcmp_cpuid_str(supported_cpuids[i], cpuid) == 0;
if (cached_snc_supported)
break;
}
return is_graniterapids;
free(cpuid);
}
static bool x86__is_snc_supported(void)
{
pthread_once(&snc_support_once, init_snc_support);
return cached_snc_supported;
}
static struct perf_cpu_map *read_sysfs_cpu_map(const char *sysfs_path)
@ -52,49 +68,58 @@ static struct perf_cpu_map *read_sysfs_cpu_map(const char *sysfs_path)
return cpus;
}
static int cached_snc_nodes;
static pthread_once_t snc_nodes_once = PTHREAD_ONCE_INIT;
static void init_snc_nodes(void)
{
struct perf_cpu_map *node_cpus =
read_sysfs_cpu_map("devices/system/node/node0/cpulist");
struct perf_cpu_map *cache_cpus =
read_sysfs_cpu_map("devices/system/cpu/cpu0/cache/index3/shared_cpu_list");
if (node_cpus && cache_cpus)
cached_snc_nodes = perf_cpu_map__nr(cache_cpus) / perf_cpu_map__nr(node_cpus);
else
cached_snc_nodes = 0;
perf_cpu_map__put(cache_cpus);
perf_cpu_map__put(node_cpus);
}
static int snc_nodes_per_l3_cache(void)
{
static bool checked_snc;
static int snc_nodes;
pthread_once(&snc_nodes_once, init_snc_nodes);
return cached_snc_nodes;
}
if (!checked_snc) {
struct perf_cpu_map *node_cpus =
read_sysfs_cpu_map("devices/system/node/node0/cpulist");
struct perf_cpu_map *cache_cpus =
read_sysfs_cpu_map("devices/system/cpu/cpu0/cache/index3/shared_cpu_list");
static int cached_num_chas;
static pthread_once_t num_chas_once = PTHREAD_ONCE_INIT;
snc_nodes = perf_cpu_map__nr(cache_cpus) / perf_cpu_map__nr(node_cpus);
perf_cpu_map__put(cache_cpus);
perf_cpu_map__put(node_cpus);
checked_snc = true;
static void init_num_chas(void)
{
int fd = perf_pmu__event_source_devices_fd();
struct io_dir dir;
struct io_dirent64 *dent;
if (fd < 0) {
cached_num_chas = -1;
return;
}
return snc_nodes;
io_dir__init(&dir, fd);
while ((dent = io_dir__readdir(&dir)) != NULL) {
/* Note, dent->d_type will be DT_LNK and so isn't a useful filter. */
if (strstarts(dent->d_name, "uncore_cha_"))
cached_num_chas++;
}
close(fd);
}
static int num_chas(void)
{
static bool checked_chas;
static int num_chas;
if (!checked_chas) {
int fd = perf_pmu__event_source_devices_fd();
struct io_dir dir;
struct io_dirent64 *dent;
if (fd < 0)
return -1;
io_dir__init(&dir, fd);
while ((dent = io_dir__readdir(&dir)) != NULL) {
/* Note, dent->d_type will be DT_LNK and so isn't a useful filter. */
if (strstarts(dent->d_name, "uncore_cha_"))
num_chas++;
}
close(fd);
checked_chas = true;
}
return num_chas;
pthread_once(&num_chas_once, init_num_chas);
return cached_num_chas;
}
#define MAX_SNCS 6
@ -121,46 +146,78 @@ static int uncore_cha_snc(struct perf_pmu *pmu)
return 0;
}
chas_per_node = num_cha / snc_nodes;
if (chas_per_node == 0) {
pr_warning("Unexpected: chas_per_node is 0 (num_cha=%d, snc_nodes=%d)\n",
num_cha, snc_nodes);
return 0;
}
cha_snc = cha_num / chas_per_node;
/* Range check cha_snc. for unexpected out of bounds. */
return cha_snc >= MAX_SNCS ? 0 : cha_snc;
}
static const u8 *cached_imc_snc_map;
static size_t cached_imc_snc_map_len;
static pthread_once_t imc_snc_map_once = PTHREAD_ONCE_INIT;
static void init_snc_map(void)
{
int snc_nodes = snc_nodes_per_l3_cache();
char *cpuid;
static const u8 spr_emr_snc2_map[] = { 0, 0, 1, 1 };
static const u8 gnr_snc2_map[] = { 1, 1, 0, 0 };
static const u8 snc3_map[] = { 1, 1, 0, 0, 2, 2 };
switch (snc_nodes) {
case 2:
cpuid = get_cpuid_str((struct perf_cpu){ 0 });
if (cpuid) {
if (strcmp_cpuid_str(GENUINE_INTEL_SPR, cpuid) == 0 ||
strcmp_cpuid_str(GENUINE_INTEL_EMR, cpuid) == 0) {
cached_imc_snc_map = spr_emr_snc2_map;
cached_imc_snc_map_len = ARRAY_SIZE(spr_emr_snc2_map);
} else if (strcmp_cpuid_str(GENUINE_INTEL_GNR, cpuid) == 0) {
cached_imc_snc_map = gnr_snc2_map;
cached_imc_snc_map_len = ARRAY_SIZE(gnr_snc2_map);
}
free(cpuid);
}
break;
case 3:
cached_imc_snc_map = snc3_map;
cached_imc_snc_map_len = ARRAY_SIZE(snc3_map);
break;
default:
/* Error or no lookup support for SNC with >3 nodes. */
break;
}
if (!cached_imc_snc_map)
pr_warning("Unexpected: can not find snc map config\n");
}
static int uncore_imc_snc(struct perf_pmu *pmu)
{
// Compute the IMC SNC using lookup tables.
unsigned int imc_num;
int snc_nodes = snc_nodes_per_l3_cache();
const u8 snc2_map[] = {1, 1, 0, 0, 1, 1, 0, 0};
const u8 snc3_map[] = {1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2};
const u8 *snc_map;
size_t snc_map_len;
switch (snc_nodes) {
case 2:
snc_map = snc2_map;
snc_map_len = ARRAY_SIZE(snc2_map);
break;
case 3:
snc_map = snc3_map;
snc_map_len = ARRAY_SIZE(snc3_map);
break;
default:
/* Error or no lookup support for SNC with >3 nodes. */
if (snc_nodes <= 1)
return 0;
}
pthread_once(&imc_snc_map_once, init_snc_map);
/* Compute SNC for PMU. */
if (sscanf(pmu->name, "uncore_imc_%u", &imc_num) != 1) {
pr_warning("Unexpected: unable to compute IMC number '%s'\n", pmu->name);
return 0;
}
if (imc_num >= snc_map_len) {
pr_warning("Unexpected IMC %d for SNC%d mapping\n", imc_num, snc_nodes);
if (!cached_imc_snc_map)
return 0;
}
return snc_map[imc_num];
return cached_imc_snc_map[imc_num % cached_imc_snc_map_len];
}
static int uncore_cha_imc_compute_cpu_adjust(int pmu_snc)
@ -200,7 +257,9 @@ static int uncore_cha_imc_compute_cpu_adjust(int pmu_snc)
return cpu_adjust[pmu_snc];
}
static void gnr_uncore_cha_imc_adjust_cpumask_for_snc(struct perf_pmu *pmu, bool cha)
static pthread_mutex_t pmu_adjust_mutex = PTHREAD_MUTEX_INITIALIZER;
static void uncore_cha_imc_adjust_cpumask_for_snc(struct perf_pmu *pmu, bool cha)
{
// With sub-NUMA clustering (SNC) there is a NUMA node per SNC in the
// topology. For example, a two socket graniterapids machine may be set
@ -231,9 +290,11 @@ static void gnr_uncore_cha_imc_adjust_cpumask_for_snc(struct perf_pmu *pmu, bool
return;
}
pthread_mutex_lock(&pmu_adjust_mutex);
pmu_snc = cha ? uncore_cha_snc(pmu) : uncore_imc_snc(pmu);
if (pmu_snc == 0) {
// No adjustment necessary for the first SNC.
pthread_mutex_unlock(&pmu_adjust_mutex);
return;
}
@ -242,8 +303,10 @@ static void gnr_uncore_cha_imc_adjust_cpumask_for_snc(struct perf_pmu *pmu, bool
// Hold onto the perf_cpu_map globally to avoid recomputation.
cpu_adjust = uncore_cha_imc_compute_cpu_adjust(pmu_snc);
adjusted[pmu_snc] = perf_cpu_map__empty_new(perf_cpu_map__nr(pmu->cpus));
if (!adjusted[pmu_snc])
if (!adjusted[pmu_snc]) {
pthread_mutex_unlock(&pmu_adjust_mutex);
return;
}
}
perf_cpu_map__for_each_cpu(cpu, idx, pmu->cpus) {
@ -263,11 +326,14 @@ static void gnr_uncore_cha_imc_adjust_cpumask_for_snc(struct perf_pmu *pmu, bool
perf_cpu_map__put(pmu->cpus);
pmu->cpus = perf_cpu_map__get(adjusted[pmu_snc]);
pthread_mutex_unlock(&pmu_adjust_mutex);
}
void perf_pmu__arch_init(struct perf_pmu *pmu)
{
struct perf_pmu_caps *ldlat_cap;
bool swfilt_format;
if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) {
pmu->auxtrace = true;
@ -283,7 +349,10 @@ void perf_pmu__arch_init(struct perf_pmu *pmu)
if (strcmp(pmu->name, "ibs_op"))
return;
pmu->mem_events = perf_mem_events_amd;
swfilt_format = perf_pmu__has_format(pmu, "swfilt");
pmu->mem_events = swfilt_format ?
perf_mem_events_amd_swfilt :
perf_mem_events_amd;
if (!perf_pmu__caps_parse(pmu))
return;
@ -293,18 +362,25 @@ void perf_pmu__arch_init(struct perf_pmu *pmu)
return;
perf_mem_events__loads_ldlat = 0;
pmu->mem_events = perf_mem_events_amd_ldlat;
pmu->mem_events = swfilt_format ?
perf_mem_events_amd_ldlat_swfilt :
perf_mem_events_amd_ldlat;
} else {
if (pmu->is_core) {
if (perf_pmu__have_event(pmu, "mem-loads-aux"))
pmu->mem_events = perf_mem_events_intel_aux;
else
pmu->mem_events = perf_mem_events_intel;
} else if (x86__is_intel_graniterapids()) {
if (strstarts(pmu->name, "uncore_cha_"))
gnr_uncore_cha_imc_adjust_cpumask_for_snc(pmu, /*cha=*/true);
else if (strstarts(pmu->name, "uncore_imc_"))
gnr_uncore_cha_imc_adjust_cpumask_for_snc(pmu, /*cha=*/false);
} else if (x86__is_snc_supported()) {
int snc_nodes = snc_nodes_per_l3_cache();
if (snc_nodes == 2 || snc_nodes == 3) {
if (strstarts(pmu->name, "uncore_cha_"))
uncore_cha_imc_adjust_cpumask_for_snc(pmu, /*cha=*/true);
else if (strstarts(pmu->name, "uncore_imc_") &&
!strstarts(pmu->name, "uncore_imc_free_running"))
uncore_cha_imc_adjust_cpumask_for_snc(pmu, /*cha=*/false);
}
}
}
}

View File

@ -37,8 +37,7 @@ bool topdown_sys_has_perf_metrics(void)
bool arch_is_topdown_slots(const struct evsel *evsel)
{
return evsel->core.attr.type == PERF_TYPE_RAW &&
evsel->core.attr.config == TOPDOWN_SLOTS &&
evsel->core.attr.config1 == 0;
evsel->core.attr.config == TOPDOWN_SLOTS;
}
bool arch_is_topdown_metrics(const struct evsel *evsel)

View File

@ -3,6 +3,7 @@ perf-bench-y += sched-pipe.o
perf-bench-y += sched-seccomp-notify.o
perf-bench-y += syscall.o
perf-bench-y += mem-functions.o
perf-bench-y += atomic.o
perf-bench-y += futex.o
perf-bench-y += futex-hash.o
perf-bench-y += futex-wake.o

299
tools/perf/bench/atomic.c Normal file
View File

@ -0,0 +1,299 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2026 Changbin Du <changbin.du@gmail.com>
*
* Benchmarks for atomic read-modify-write operations.
*
* Measures throughput (ops/sec) of contended atomic operations on a
* single shared counter across multiple threads. Each thread performs
* a hot loop of the selected operation -- compare-and-swap (cas) or
* fetch-add (inc) -- competing with all other threads for the same
* cache line. Threads run for a fixed runtime, so a system that
* cannot make progress under heavy contention reports a low (or
* zero) throughput instead of hanging.
*/
#include "bench.h"
#include <linux/compiler.h>
#include "../util/debug.h"
#ifndef HAVE_PTHREAD_BARRIER
int bench_atomic_cas(int argc __maybe_unused, const char **argv __maybe_unused)
{
pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__);
return 0;
}
int bench_atomic_inc(int argc __maybe_unused, const char **argv __maybe_unused)
{
pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__);
return 0;
}
#else /* HAVE_PTHREAD_BARRIER */
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <inttypes.h>
#include <err.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/time64.h>
#include <perf/cpumap.h>
#include <subcmd/parse-options.h>
#include "../util/stat.h"
static unsigned int threads; /* 0: default to min(2, online CPUs) */
static unsigned int runtime = 2; /* seconds per repeat */
static const struct option options[] = {
OPT_UINTEGER('T', "threads", &threads,
"Number of contending threads (default: 2, or 1 on single CPU)"),
OPT_UINTEGER('R', "runtime", &runtime,
"Runtime of each repeat in seconds (default: 2)"),
OPT_END()
};
static const char * const cas_usage[] = {
"perf bench atomic cas <options>",
NULL
};
static const char * const inc_usage[] = {
"perf bench atomic inc <options>",
NULL
};
enum atomic_op {
OP_CAS,
OP_INC,
};
static int bench_op = OP_CAS;
/*
* The termination flag is polled between batches only, so that the
* check does not perturb the measured loop.
*/
#define BATCH_OPS 1024
static unsigned long shared_counter __aligned(64);
static pthread_barrier_t start_barrier __aligned(64);
static bool done;
struct worker_stats {
u64 runtime_ns;
u64 ops;
};
static void cas_batch(void)
{
unsigned long i;
/*
* Each iteration counts as one successful compare-and-swap;
* retries and the loads between them are not counted.
*/
for (i = 0; i < BATCH_OPS; i++) {
unsigned long old_val, new_val;
old_val = __atomic_load_n(&shared_counter, __ATOMIC_RELAXED);
do {
new_val = old_val + 1;
} while (!__atomic_compare_exchange_n(&shared_counter, &old_val,
new_val, false,
__ATOMIC_RELAXED,
__ATOMIC_RELAXED));
}
}
static void inc_batch(void)
{
unsigned long i;
for (i = 0; i < BATCH_OPS; i++)
__atomic_fetch_add(&shared_counter, 1, __ATOMIC_RELAXED);
}
static void *worker(void *arg)
{
struct worker_stats *ws = (struct worker_stats *)arg;
struct timespec tstart, tend;
u64 ops = 0;
pthread_barrier_wait(&start_barrier);
clock_gettime(CLOCK_MONOTONIC, &tstart);
while (!__atomic_load_n(&done, __ATOMIC_RELAXED)) {
switch (bench_op) {
case OP_CAS:
cas_batch();
break;
case OP_INC:
inc_batch();
break;
default:
BUG_ON(1);
break;
}
ops += BATCH_OPS;
}
clock_gettime(CLOCK_MONOTONIC, &tend);
ws->runtime_ns = (u64)(tend.tv_sec - tstart.tv_sec) * NSEC_PER_SEC +
(tend.tv_nsec - tstart.tv_nsec);
ws->ops = ops;
return NULL;
}
static void print_default_format(struct worker_stats *wstats,
struct stats *throughput_stats)
{
double thru_avg, thru_stddev;
printf(" Threads: %u, runtime: %u sec, repeats: %u (warmup: 1)\n",
threads, runtime, bench_repeat);
thru_avg = avg_stats(throughput_stats);
thru_stddev = stddev_stats(throughput_stats);
printf(" Avg throughput: %'.0f ops/sec (+- %.2f%%)\n",
thru_avg, rel_stddev_stats(thru_stddev, thru_avg));
/*
* Per-thread operation counts from the last measured repeat show
* whether any thread failed to make progress under contention.
*/
if (threads > 1) {
u64 min_ops = UINT64_MAX, max_ops = 0, total_ops = 0;
for (unsigned int t = 0; t < threads; t++) {
if (wstats[t].ops < min_ops)
min_ops = wstats[t].ops;
if (wstats[t].ops > max_ops)
max_ops = wstats[t].ops;
total_ops += wstats[t].ops;
}
printf(" Per-thread ops (last repeat):\n");
printf(" fastest: %'" PRIu64 " ops\n", max_ops);
printf(" slowest: %'" PRIu64 " ops\n", min_ops);
printf(" avg: %'" PRIu64 " ops\n", total_ops / threads);
}
}
static int run_benchmark(void)
{
pthread_t *thread_ids;
struct worker_stats *wstats;
struct stats throughput_stats;
unsigned int r, t;
thread_ids = calloc(threads, sizeof(pthread_t));
if (!thread_ids)
err(EXIT_FAILURE, "calloc");
wstats = calloc(threads, sizeof(struct worker_stats));
if (!wstats)
err(EXIT_FAILURE, "calloc");
init_stats(&throughput_stats);
for (r = 0; r < bench_repeat + 1; r++) {
u64 max_runtime_ns = 0, total_ops = 0;
double throughput;
shared_counter = 0;
__atomic_store_n(&done, false, __ATOMIC_RELAXED);
pthread_barrier_init(&start_barrier, NULL, threads);
for (t = 0; t < threads; t++) {
if (pthread_create(&thread_ids[t], NULL,
worker, &wstats[t]))
err(EXIT_FAILURE, "pthread_create");
}
sleep(runtime);
__atomic_store_n(&done, true, __ATOMIC_RELAXED);
for (t = 0; t < threads; t++)
pthread_join(thread_ids[t], NULL);
pthread_barrier_destroy(&start_barrier);
for (t = 0; t < threads; t++) {
total_ops += wstats[t].ops;
if (wstats[t].runtime_ns > max_runtime_ns)
max_runtime_ns = wstats[t].runtime_ns;
}
/*
* Exclude the first repeat (warmup) from statistics so
* that cache-cold and lazy-init effects are not counted.
*/
if (r > 0 && max_runtime_ns) {
throughput = (double)total_ops /
((double)max_runtime_ns / NSEC_PER_SEC);
update_stats(&throughput_stats, (u64)throughput);
}
}
switch (bench_format) {
case BENCH_FORMAT_DEFAULT:
print_default_format(wstats, &throughput_stats);
break;
case BENCH_FORMAT_SIMPLE:
printf("%.0f\n", avg_stats(&throughput_stats));
break;
default:
fprintf(stderr, "Unknown format: %d\n", bench_format);
exit(EXIT_FAILURE);
}
free(thread_ids);
free(wstats);
return 0;
}
static int run_atomic_bench(int argc, const char **argv,
const char * const *usage)
{
struct perf_cpu_map *cpu;
if (parse_options(argc, argv, options, usage, 0)) {
usage_with_options(usage, options);
exit(EXIT_FAILURE);
}
if (!threads) { /* default to 2 threads (1 on a single-CPU machine) */
cpu = perf_cpu_map__new_online_cpus();
threads = (cpu && perf_cpu_map__nr(cpu) > 1) ? 2 : 1;
perf_cpu_map__put(cpu);
}
if (runtime < 1) {
fprintf(stderr, "Invalid runtime: %u\n", runtime);
return 1;
}
return run_benchmark();
}
int bench_atomic_cas(int argc, const char **argv)
{
bench_op = OP_CAS;
return run_atomic_bench(argc, argv, cas_usage);
}
int bench_atomic_inc(int argc, const char **argv)
{
bench_op = OP_INC;
return run_atomic_bench(argc, argv, inc_usage);
}
#endif /* HAVE_PTHREAD_BARRIER */

View File

@ -30,6 +30,8 @@ int bench_mem_memcpy(int argc, const char **argv);
int bench_mem_memset(int argc, const char **argv);
int bench_mem_mmap(int argc, const char **argv);
int bench_mem_find_bit(int argc, const char **argv);
int bench_atomic_cas(int argc, const char **argv);
int bench_atomic_inc(int argc, const char **argv);
int bench_futex_hash(int argc, const char **argv);
int bench_futex_wake(int argc, const char **argv);
int bench_futex_wake_parallel(int argc, const char **argv);

View File

@ -14,6 +14,17 @@
#include <sys/types.h>
#include <linux/futex.h>
/*
* SYS_futex is expected from system C library, in glibc some 32-bit
* architectures (e.g. RV32) are using 64-bit time_t, therefore it doesn't have
* SYS_futex defined but just SYS_futex_time64. Define SYS_futex as
* SYS_futex_time64 in this situation to ensure the compilation and the
* compatibility.
*/
#if !defined(SYS_futex) && defined(SYS_futex_time64)
#define SYS_futex SYS_futex_time64
#endif
struct bench_futex_parameters {
bool silent;
bool fshared;

View File

@ -1419,6 +1419,7 @@ static void worker_process(int process_nr)
bind_to_cpumask(td->bind_cpumask);
pthreads = calloc(g->p.nr_threads, sizeof(pthread_t));
BUG_ON(!pthreads);
process_data = setup_private_data(g->p.bytes_process);
if (g->p.show_details >= 3) {
@ -1625,6 +1626,7 @@ static int __bench_numa(const char *name)
return -1;
pids = calloc(g->p.nr_proc, sizeof(*pids));
BUG_ON(!pids);
pid = -1;
if (g->p.serialize_startup) {

View File

@ -338,9 +338,9 @@ int bench_sched_messaging(int argc, const char **argv)
switch (bench_format) {
case BENCH_FORMAT_DEFAULT:
printf("# %d sender and receiver %s per group\n",
printf("# %u sender and receiver %s per group\n",
num_fds, thread_mode ? "threads" : "processes");
printf("# %d groups == %d %s run\n\n",
printf("# %u groups == %u %s run\n\n",
num_groups, num_groups * 2 * num_fds,
thread_mode ? "threads" : "processes");
printf(" %14s: %lu.%03lu [sec]\n", "Total time",

View File

@ -6,44 +6,53 @@
* look up and read DSOs and symbol information and display
* a histogram of results, along various sorting keys.
*/
#include "builtin.h"
#include "perf.h"
#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/debug.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/annotate.h"
#include "util/annotate-data.h"
#include "util/event.h"
#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/sort.h"
#include "util/hist.h"
#include "util/dso.h"
#include "util/machine.h"
#include "util/map.h"
#include "util/session.h"
#include "util/tool.h"
#include "util/data.h"
#include "arch/common.h"
#include "util/block-range.h"
#include "util/map_symbol.h"
#include "util/branch.h"
#include "util/util.h"
#include "ui/progress.h"
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <errno.h>
#include <linux/bitmap.h>
#include <linux/err.h>
#include <inttypes.h>
#include <linux/list.h>
#include <linux/rbtree.h>
#include <subcmd/parse-options.h>
#include "arch/common.h"
#include "builtin.h"
#include "perf.h"
#include "ui/keysyms.h"
#include "ui/progress.h"
#include "ui/ui.h"
#include "util/annotate-data.h"
#include "util/annotate.h"
#include "util/block-range.h"
#include "util/branch.h"
#include "util/data.h"
#include "util/debug.h"
#include "util/dso.h"
#include "util/event.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/hist.h"
#include "util/machine.h"
#include "util/map.h"
#include "util/map_symbol.h"
#include "util/session.h"
#include "util/sort.h"
#include "util/symbol.h"
#include "util/tool.h"
#include "util/util.h"
#ifndef HAVE_SLANG_SUPPORT
#undef K_LEFT
#define K_LEFT -1000
#undef K_RIGHT
#define K_RIGHT -2000
#endif
struct perf_annotate {
struct perf_tool tool;
@ -52,7 +61,7 @@ struct perf_annotate {
bool use_tui;
#endif
bool use_stdio, use_stdio2;
#ifdef HAVE_GTK2_SUPPORT
#ifdef HAVE_GTK4_SUPPORT
bool use_gtk;
#endif
bool skip_missing;
@ -712,13 +721,15 @@ int cmd_annotate(int argc, const char **argv)
OPT_BOOLEAN('q', "quiet", &quiet, "do now show any warnings or messages"),
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"),
#ifdef HAVE_GTK2_SUPPORT
#ifdef HAVE_GTK4_SUPPORT
OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
#endif
#ifdef HAVE_SLANG_SUPPORT
OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
#endif
OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
OPT_BOOLEAN(0, "weights", &symbol_conf.annotate_weight,
"Show or hide weight columns in annotation. Default show if non zero."),
OPT_BOOLEAN(0, "stdio2", &annotate.use_stdio2, "Use the stdio interface"),
OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
"don't load vmlinux even if found"),
@ -788,6 +799,7 @@ int cmd_annotate(int argc, const char **argv)
set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE);
set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE);
symbol_conf.annotate_weight = true;
annotation_options__init();
@ -828,7 +840,7 @@ int cmd_annotate(int argc, const char **argv)
if (annotate_check_args() < 0)
return -EINVAL;
#ifdef HAVE_GTK2_SUPPORT
#ifdef HAVE_GTK4_SUPPORT
if (symbol_conf.show_nr_samples && annotate.use_gtk) {
pr_err("--show-nr-samples is not available in --gtk mode at this time\n");
return ret;
@ -873,6 +885,14 @@ int cmd_annotate(int argc, const char **argv)
annotate.session = perf_session__new(&data, &annotate.tool);
if (IS_ERR(annotate.session))
return PTR_ERR(annotate.session);
/*
* Hardware tracing (e.g., ARM SPE) may synthesize multiple events per
* instruction. When data type profiling is enabled, default to synthesizing
* at most one event (equivalent to --itrace=i1i) to prevent skewed
* statistics.
*/
if (annotate.data_type && !itrace_synth_opts.set)
itrace_synth_opts.default_single_event_per_ip = true;
annotate.session->itrace_synth_opts = &itrace_synth_opts;
@ -898,7 +918,7 @@ int cmd_annotate(int argc, const char **argv)
else if (annotate.use_tui)
use_browser = 1;
#endif
#ifdef HAVE_GTK2_SUPPORT
#ifdef HAVE_GTK4_SUPPORT
else if (annotate.use_gtk)
use_browser = 2;
#endif

View File

@ -14,6 +14,7 @@
* syscall ... System call performance
* mem ... memory access performance
* numa ... NUMA scheduling and MM performance
* atomic ... Atomic operation performance
* futex ... Futex performance
* epoll ... Event poll performance
*/
@ -115,6 +116,13 @@ static const struct bench uprobe_benchmarks[] = {
{ NULL, NULL, NULL },
};
static const struct bench atomic_benchmarks[] = {
{ "cas", "Benchmark CAS (compare-and-swap) operations", bench_atomic_cas },
{ "inc", "Benchmark atomic fetch-add operations", bench_atomic_inc },
{ "all", "Run all atomic benchmarks", NULL },
{ NULL, NULL, NULL }
};
struct collection {
const char *name;
const char *summary;
@ -128,6 +136,7 @@ static const struct collection collections[] = {
#ifdef HAVE_LIBNUMA_SUPPORT
{ "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
#endif
{ "atomic", "Atomic operation benchmarks", atomic_benchmarks },
{"futex", "Futex stressing benchmarks", futex_benchmarks },
#ifdef HAVE_EVENTFD_SUPPORT
{"epoll", "Epoll stressing benchmarks", epoll_benchmarks },

View File

@ -87,6 +87,7 @@ static bool dso__skip_buildid(struct dso *dso, int with_hits)
static int perf_session__list_build_ids(bool force, bool with_hits)
{
struct perf_session *session;
bool has_auxtrace, has_build_id;
struct perf_data data = {
.path = input_name,
.mode = PERF_DATA_MODE_READ,
@ -118,11 +119,19 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
* We take all buildids when the file contains AUX area tracing data
* because we do not decode the trace because it would take too long.
*/
if (!perf_data__is_pipe(&data) &&
perf_header__has_feat(&session->header, HEADER_AUXTRACE))
has_auxtrace = !perf_data__is_pipe(&data) &&
perf_header__has_feat(&session->header, HEADER_AUXTRACE);
has_build_id = perf_header__has_feat(&session->header, HEADER_BUILD_ID);
if (has_auxtrace)
with_hits = false;
if (!perf_header__has_feat(&session->header, HEADER_BUILD_ID))
/*
* Without a build-ID header, the event stream is processed below to find
* build IDs in MMAP2 records. For AUX data keep all DSOs because the trace
* is not decoded and consequently none of them can be marked as hit.
*/
if (!has_build_id && !has_auxtrace)
with_hits = true;
if (zstd_init(&(session->zstd_data), 0) < 0)
@ -132,7 +141,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
* in pipe-mode, the only way to get the buildids is to parse
* the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
*/
if (with_hits || perf_data__is_pipe(&data))
if (with_hits || perf_data__is_pipe(&data) || !has_build_id)
perf_session__process_events(session);
perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);

View File

@ -14,6 +14,7 @@
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <asm/bug.h>
#include <linux/compiler.h>
@ -49,6 +50,7 @@
#include "thread.h"
#include "tool.h"
#include "ui/browsers/hists.h"
#include "ui/keysyms.h"
#include "ui/progress.h"
#include "ui/ui.h"
#include "util/annotate.h"
@ -71,8 +73,10 @@ struct perf_c2c {
bool show_src;
bool show_all;
bool show_mem_region;
bool use_stdio;
bool stats_only;
bool function_view;
bool symbol_full;
bool stitch_lbr;
@ -247,6 +251,18 @@ static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,
}
}
static void c2c_he__set_mem_region(struct c2c_hist_entry *c2c_he,
unsigned int mem_region)
{
if (WARN_ONCE(mem_region > PERF_MEM_REGION_MEM7,
"WARNING: invalid memory region ID\n"))
return;
/* Update mem_region only if it really accesses memory */
if (mem_region >= PERF_MEM_REGION_MMIO)
c2c_he->mem_region = mem_region;
}
static void compute_stats(struct c2c_hist_entry *c2c_he,
struct c2c_stats *stats,
u64 weight)
@ -305,6 +321,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
struct addr_location al;
struct mem_info *mi = NULL;
struct callchain_cursor *cursor;
unsigned int mem_region;
int ret;
addr_location__init(&al);
@ -332,6 +349,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
}
c2c_decode_stats(&stats, mi);
mem_region = mem_info__data_src(mi)->mem_region;
he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops,
&al, NULL, NULL, mi, NULL,
@ -348,6 +366,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
c2c_he__set_cpu(c2c_he, sample);
c2c_he__set_node(c2c_he, sample);
c2c_he__set_evsel(c2c_he, evsel);
c2c_he__set_mem_region(c2c_he, mem_region);
hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
@ -401,6 +420,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
c2c_he__set_cpu(c2c_he, sample);
c2c_he__set_node(c2c_he, sample);
c2c_he__set_evsel(c2c_he, evsel);
c2c_he__set_mem_region(c2c_he, mem_region);
hists__inc_nr_samples(&c2c_hists->hists, he->filtered);
ret = hist_entry__append_callchain(he, sample);
@ -539,6 +559,45 @@ dcacheline_node_count(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
return scnprintf(hpp->buf, hpp->size, "%*lu", width, c2c_he->paddr_cnt);
}
static int
dcacheline_node_mem_region(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he)
{
int width = c2c_width(fmt, hpp, he->hists);
struct c2c_hist_entry *c2c_he;
unsigned int mem_region;
char buf[20];
c2c_he = container_of(he, struct c2c_hist_entry, he);
mem_region = c2c_he->mem_region;
switch (mem_region) {
case PERF_MEM_REGION_NA:
case PERF_MEM_REGION_RSVD:
scnprintf(buf, sizeof(buf), "N/A");
break;
case PERF_MEM_REGION_MMIO:
scnprintf(buf, sizeof(buf), "MMIO");
break;
case PERF_MEM_REGION_MEM0:
case PERF_MEM_REGION_MEM1:
case PERF_MEM_REGION_MEM2:
case PERF_MEM_REGION_MEM3:
case PERF_MEM_REGION_MEM4:
case PERF_MEM_REGION_MEM5:
case PERF_MEM_REGION_MEM6:
case PERF_MEM_REGION_MEM7:
scnprintf(buf, sizeof(buf), "Mem-%d",
mem_region - PERF_MEM_REGION_MEM0);
break;
default:
scnprintf(buf, sizeof(buf), "N/A");
break;
}
return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
}
static int offset_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he)
{
@ -1359,6 +1418,14 @@ static struct c2c_dimension dim_dcacheline_node = {
.width = 4,
};
static struct c2c_dimension dim_dcacheline_mem_region = {
.header = HEADER_LOW("Region"),
.name = "dcacheline_mem_region",
.cmp = empty_cmp,
.entry = dcacheline_node_mem_region,
.width = 6,
};
static struct c2c_dimension dim_dcacheline_count = {
.header = HEADER_LOW("PA cnt"),
.name = "dcacheline_count",
@ -1790,6 +1857,7 @@ static struct c2c_dimension dim_dcacheline_num_empty = {
static struct c2c_dimension *dimensions[] = {
&dim_dcacheline,
&dim_dcacheline_mem_region,
&dim_dcacheline_node,
&dim_dcacheline_count,
&dim_offset,
@ -2087,6 +2155,11 @@ static int c2c_hists__reinit(struct c2c_hists *c2c_hists,
return ret;
}
static void c2c_hists__exit(struct c2c_hists *c2c_hists)
{
perf_hpp__reset_output_field(&c2c_hists->list);
}
#define DISPLAY_LINE_LIMIT 0.001
static u8 filter_display(u32 val, u32 sum)
@ -2495,7 +2568,7 @@ static void print_pareto(FILE *out, struct perf_env *env)
ret = hpp_list__parse(&hpp_list, cl_output, /*evlist=*/NULL, env);
if (WARN_ONCE(ret, "failed to setup sort entries\n"))
return;
goto out;
nd = rb_first_cached(&c2c.hists.hists.entries);
@ -2509,6 +2582,9 @@ static void print_pareto(FILE *out, struct perf_env *env)
c2c_he = container_of(he, struct c2c_hist_entry, he);
print_cacheline(c2c_he->hists, he, &hpp_list, out);
}
out:
perf_hpp__reset_output_field(&hpp_list);
}
static void print_c2c_info(FILE *out, struct perf_session *session)
@ -2530,7 +2606,75 @@ static void print_c2c_info(FILE *out, struct perf_session *session)
fprintf(out, " Cacheline data grouping : %s\n", c2c.cl_sort);
}
static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
static void print_memory_ranges_info(FILE *out, struct perf_session *session)
{
struct perf_env *env = perf_session__env(session);
int nr_ranges = 0;
if (!perf_header__has_feat(&session->header, HEADER_MEMORY_RANGES))
return;
nr_ranges = env->nr_memory_ranges;
if (nr_ranges == 0) {
pr_debug("No memory ranges found, skipping\n");
return;
}
fprintf(out, "\n");
fprintf(out, "=================================================\n");
fprintf(out, " Memory Ranges \n");
fprintf(out, "=================================================\n");
for (int i = 0; i < nr_ranges; i++) {
struct memory_range *r = &env->memory_ranges[i];
fprintf(out, "Range %d: [0x%016" PRIx64 "-0x%016" PRIx64 "] Node %d, local region id %u, remote region id %u\n",
i, r->base, r->base + r->length - 1, r->node,
r->local_region_id, r->remote_region_id);
}
}
static void c2c_function__unfold_all(struct rb_root_cached *root)
{
struct rb_node *nd;
for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
if (!he->has_children)
continue;
he->unfolded = true;
c2c_function__unfold_all(&he->hroot_out);
}
}
static int perf_c2c__function_fprintf(FILE *out)
{
bool saved_use_callchain = symbol_conf.use_callchain;
struct hists *hists;
int ret;
/* Function-view entries aggregate samples and never display callchains. */
symbol_conf.use_callchain = false;
ret = c2c_function__build(&c2c.hists, c2c.cl_sort, c2c.symbol_full,
&hists);
if (ret) {
if (ret == -EOPNOTSUPP)
pr_err("The function view requires iaddr in --coalesce.\n");
else
pr_err("Failed to build function view hierarchy (ret=%d)\n", ret);
goto out;
}
/* Match fold signs to hists__fprintf()'s forced child traversal. */
c2c_function__unfold_all(&hists->entries);
hists__fprintf(hists, true, 0, 0, 0, out, true);
c2c_function__reset();
out:
symbol_conf.use_callchain = saved_use_callchain;
return ret;
}
static int perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
{
setup_pager();
@ -2541,7 +2685,19 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
print_c2c_info(out, session);
if (c2c.stats_only)
return;
return 0;
if (c2c.function_view) {
fprintf(out, "\n");
fprintf(out, "=================================================\n");
fprintf(out, " Shared Data Functions Table\n");
fprintf(out, "=================================================\n");
fprintf(out, "#\n");
return perf_c2c__function_fprintf(out);
}
print_memory_ranges_info(out, session);
fprintf(out, "\n");
fprintf(out, "=================================================\n");
@ -2558,6 +2714,7 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session)
fprintf(out, "#\n");
print_pareto(out, perf_session__env(session));
return 0;
}
#ifdef HAVE_SLANG_SUPPORT
@ -2794,18 +2951,18 @@ static int perf_c2c__hists_browse(struct hists *hists)
return 0;
}
static void perf_c2c_display(struct perf_session *session)
static int perf_c2c_display(struct perf_session *session)
{
if (use_browser == 0)
perf_c2c__hists_fprintf(stdout, session);
else
perf_c2c__hists_browse(&c2c.hists.hists);
return perf_c2c__hists_fprintf(stdout, session);
return perf_c2c__hists_browse(&c2c.hists.hists);
}
#else
static void perf_c2c_display(struct perf_session *session)
static int perf_c2c_display(struct perf_session *session)
{
use_browser = 0;
perf_c2c__hists_fprintf(stdout, session);
return perf_c2c__hists_fprintf(stdout, session);
}
#endif /* HAVE_SLANG_SUPPORT */
@ -2853,8 +3010,11 @@ static int ui_quirks(void)
/* Fix the zero line for dcacheline column. */
buf = fill_line(chk_double_cl ? "Double-Cacheline" : "Cacheline",
dim_dcacheline.width +
(c2c.show_mem_region ?
dim_dcacheline_mem_region.width : 0) +
dim_dcacheline_node.width +
dim_dcacheline_count.width + 4);
dim_dcacheline_count.width +
(c2c.show_mem_region ? 6 : 4));
if (!buf)
return -ENOMEM;
@ -3081,6 +3241,8 @@ static int perf_c2c__report(int argc, const char **argv)
OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
OPT_BOOLEAN(0, "stats", &c2c.stats_only,
"Display only statistic tables (implies --stdio)"),
OPT_BOOLEAN(0, "function", &c2c.function_view,
"Display the function view (implies --stdio)"),
OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
"Display full length of symbols"),
OPT_BOOLEAN(0, "no-source", &no_source,
@ -3106,7 +3268,8 @@ static int perf_c2c__report(int argc, const char **argv)
OPT_END()
};
int err = 0;
const char *output_str, *sort_str = NULL;
const char *sort_str = NULL;
char *output_str = NULL;
struct perf_env *env;
annotation_options__init();
@ -3119,6 +3282,11 @@ static int perf_c2c__report(int argc, const char **argv)
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc)
usage_with_options(report_c2c_usage, options);
if (c2c.stats_only && c2c.function_view) {
pr_err("--stats and --function cannot be used together.\n");
err = -EINVAL;
goto out;
}
#ifndef HAVE_SLANG_SUPPORT
c2c.use_stdio = true;
@ -3126,6 +3294,8 @@ static int perf_c2c__report(int argc, const char **argv)
if (c2c.stats_only)
c2c.use_stdio = true;
if (c2c.function_view)
c2c.use_stdio = true;
/**
* Annotation related options disassembler_style, objdump_path are set
@ -3199,6 +3369,11 @@ static int perf_c2c__report(int argc, const char **argv)
pr_debug("Failed to initialize hists\n");
goto out_session;
}
if (c2c.function_view && !c2c_function__has_iaddr(c2c.cl_sort)) {
pr_err("The function view requires iaddr in --coalesce.\n");
err = -EINVAL;
goto out_session;
}
err = c2c_hists__init(&c2c.hists, "dcacheline", 2, perf_session__env(session));
if (err) {
@ -3211,12 +3386,12 @@ static int perf_c2c__report(int argc, const char **argv)
err = setup_nodes(session);
if (err) {
pr_err("Failed setup nodes\n");
goto out_session;
goto out_hists;
}
err = mem2node__init(&c2c.mem2node, env);
if (err)
goto out_session;
goto out_hists;
err = setup_callchain(session->evlist);
if (err)
@ -3271,9 +3446,16 @@ static int perf_c2c__report(int argc, const char **argv)
goto out_mem2node;
}
if (c2c.display != DISPLAY_SNP_PEER)
output_str = "cl_idx,"
c2c.show_mem_region = perf_header__has_feat(&session->header,
HEADER_MEMORY_RANGES);
if (c2c.show_mem_region)
dim_dcacheline.header.line[0].span = 3;
if (c2c.display != DISPLAY_SNP_PEER) {
if (asprintf(&output_str,
"cl_idx,"
"dcacheline,"
"%s"
"dcacheline_node,"
"dcacheline_count,"
"percent_costly_snoop,"
@ -3285,10 +3467,17 @@ static int perf_c2c__report(int argc, const char **argv)
"ld_fbhit,ld_l1hit,ld_l2hit,"
"ld_lclhit,lcl_hitm,"
"ld_rmthit,rmt_hitm,"
"dram_lcl,dram_rmt";
else
output_str = "cl_idx,"
"dram_lcl,dram_rmt",
c2c.show_mem_region ?
"dcacheline_mem_region," : "") < 0) {
err = -ENOMEM;
goto out_mem2node;
}
} else {
if (asprintf(&output_str,
"cl_idx,"
"dcacheline,"
"%s"
"dcacheline_node,"
"dcacheline_count,"
"percent_costly_snoop,"
@ -3300,7 +3489,13 @@ static int perf_c2c__report(int argc, const char **argv)
"ld_fbhit,ld_l1hit,ld_l2hit,"
"ld_lclhit,lcl_hitm,"
"ld_rmthit,rmt_hitm,"
"dram_lcl,dram_rmt";
"dram_lcl,dram_rmt",
c2c.show_mem_region ?
"dcacheline_mem_region," : "") < 0) {
err = -ENOMEM;
goto out_mem2node;
}
}
if (c2c.display == DISPLAY_TOT_HITM)
sort_str = "tot_hitm";
@ -3314,7 +3509,7 @@ static int perf_c2c__report(int argc, const char **argv)
err = c2c_hists__reinit(&c2c.hists, output_str, sort_str, perf_session__env(session));
if (err) {
pr_err("Failed to reinitialize hists\n");
goto out_mem2node;
goto out_str;
}
ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting...");
@ -3323,19 +3518,23 @@ static int perf_c2c__report(int argc, const char **argv)
hists__output_resort_cb(&c2c.hists.hists, &prog, resort_shared_cl_cb);
err = hists__iterate_cb(&c2c.hists.hists, resort_cl_cb, perf_session__env(session));
if (err)
goto out_mem2node;
goto out_str;
ui_progress__finish();
if (ui_quirks()) {
pr_err("failed to setup UI\n");
goto out_mem2node;
goto out_str;
}
perf_c2c_display(session);
err = perf_c2c_display(session);
out_str:
free(output_str);
out_mem2node:
mem2node__exit(&c2c.mem2node);
out_hists:
c2c_hists__exit(&c2c.hists);
out_session:
perf_session__delete(session);
out:

View File

@ -51,9 +51,8 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("libLLVM", HAVE_LIBLLVM_SUPPORT),
FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT),
FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT),
FEATURE_STATUS_TIP("libperl", HAVE_LIBPERL_SUPPORT, "Deprecated, use LIBPERL=1 and install perl-ExtUtils-Embed/libperl-dev to build with it"),
FEATURE_STATUS("python-module", HAVE_PYTHON_MODULE_SUPPORT),
FEATURE_STATUS("libpfm4", HAVE_LIBPFM),
FEATURE_STATUS("libpython", HAVE_LIBPYTHON_SUPPORT),
FEATURE_STATUS("libslang", HAVE_SLANG_SUPPORT),
FEATURE_STATUS("libtraceevent", HAVE_LIBTRACEEVENT),
FEATURE_STATUS_TIP("libunwind", HAVE_LIBUNWIND_SUPPORT, "Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it"),

View File

@ -5,16 +5,20 @@
* Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
*
*/
#include "builtin.h"
#include "util/cache.h"
#include <subcmd/parse-options.h>
#include "util/debug.h"
#include "util/config.h"
#include <linux/string.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/string.h>
#include <subcmd/parse-options.h>
#include "builtin.h"
#include "util/config.h"
#include "util/debug.h"
#include "util/path.h"
static bool use_system_config, use_user_config;
@ -37,37 +41,7 @@ static struct option config_options[] = {
static int set_config(struct perf_config_set *set, const char *file_name)
{
struct perf_config_section *section = NULL;
struct perf_config_item *item = NULL;
const char *first_line = "# this file is auto-generated.";
FILE *fp;
if (set == NULL)
return -1;
fp = fopen(file_name, "w");
if (!fp)
return -1;
fprintf(fp, "%s\n", first_line);
/* overwrite configvariables */
perf_config_items__for_each_entry(&set->sections, section) {
if (!use_system_config && section->from_system_config)
continue;
fprintf(fp, "[%s]\n", section->name);
perf_config_items__for_each_entry(&section->items, item) {
if (!use_system_config && item->from_system_config)
continue;
if (item->value)
fprintf(fp, "\t%s = %s\n",
item->name, item->value);
}
}
fclose(fp);
return 0;
return perf_config_set__write(set, file_name, use_system_config);
}
static int show_spec_config(struct perf_config_set *set, const char *var)
@ -154,44 +128,6 @@ static int parse_config_arg(char *arg, char **var, char **value)
return 0;
}
int perf_config__set_variable(const char *var, const char *value)
{
char path[PATH_MAX];
char *user_config = mkpath(path, sizeof(path), "%s/.perfconfig", getenv("HOME"));
const char *config_filename;
struct perf_config_set *set;
int ret = -1;
if (use_system_config)
config_exclusive_filename = perf_etc_perfconfig();
else if (use_user_config)
config_exclusive_filename = user_config;
if (!config_exclusive_filename)
config_filename = user_config;
else
config_filename = config_exclusive_filename;
set = perf_config_set__new();
if (!set)
goto out_err;
if (perf_config_set__collect(set, config_filename, var, value) < 0) {
pr_err("Failed to add '%s=%s'\n", var, value);
goto out_err;
}
if (set_config(set, config_filename) < 0) {
pr_err("Failed to set the configs on %s\n", config_filename);
goto out_err;
}
ret = 0;
out_err:
perf_config_set__delete(set);
return ret;
}
int cmd_config(int argc, const char **argv)
{
int i, ret = -1;

View File

@ -6,23 +6,23 @@
* Copyright (c) 2020 Changbin Du <changbin.du@gmail.com>, significant enhancement.
*/
#include "builtin.h"
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <inttypes.h>
#include <math.h>
#include <poll.h>
#include <ctype.h>
#include <semaphore.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/capability.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/zalloc.h>
#include <sys/stat.h>
#include "builtin.h"
#include "debug.h"
#include <subcmd/pager.h>
#include <subcmd/parse-options.h>
@ -45,6 +45,7 @@
static volatile sig_atomic_t workload_exec_errno;
static volatile sig_atomic_t done;
static sem_t sig_sem;
static struct stats latency_stats; /* for tracepoints */
@ -53,6 +54,7 @@ static char tracing_instance[PATH_MAX]; /* Trace instance directory */
static void sig_handler(int sig __maybe_unused)
{
done = true;
sem_post(&sig_sem);
}
/*
@ -68,6 +70,7 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
{
workload_exec_errno = info->si_value.sival_int;
done = true;
sem_post(&sig_sem);
}
static bool check_ftrace_capable(void)
@ -1146,6 +1149,11 @@ static int __cmd_latency(struct perf_ftrace *ftrace)
line[0] = '\0';
while (!done) {
if (ftrace->target.use_bpf) {
sem_wait(&sig_sem);
break;
}
if (poll(&pollfd, 1, -1) < 0)
break;
@ -1852,6 +1860,8 @@ int cmd_ftrace(int argc, const char **argv)
INIT_LIST_HEAD(&ftrace.nograph_funcs);
INIT_LIST_HEAD(&ftrace.event_pair);
sem_init(&sig_sem, 0, 0);
signal(SIGINT, sig_handler);
signal(SIGUSR1, sig_handler);
signal(SIGCHLD, sig_handler);
@ -2015,5 +2025,11 @@ int cmd_ftrace(int argc, const char **argv)
delete_filter_func(&ftrace.nograph_funcs);
delete_filter_func(&ftrace.event_pair);
signal(SIGINT, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
sem_destroy(&sig_sem);
return ret;
}

View File

@ -4,28 +4,30 @@
*
* Builtin help command
*/
#include "util/cache.h"
#include "util/config.h"
#include "util/strbuf.h"
#include "builtin.h"
#include <subcmd/exec-cmd.h>
#include <subcmd/parse-options.h>
#include <subcmd/run-command.h>
#include <subcmd/help.h>
#include "util/debug.h"
#include "util/util.h"
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/zalloc.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <linux/string.h>
#include <linux/zalloc.h>
#include <sys/stat.h>
#include <unistd.h>
#include <subcmd/exec-cmd.h>
#include <subcmd/help.h>
#include <subcmd/parse-options.h>
#include <subcmd/run-command.h>
#include "builtin.h"
#include "util/config.h"
#include "util/debug.h"
#include "util/path.h"
#include "util/strbuf.h"
#include "util/util.h"
static struct man_viewer_list {
struct man_viewer_list *next;
char name[0];

View File

@ -2306,6 +2306,7 @@ static bool keep_feat(struct perf_inject *inject, int feat)
case HEADER_PMU_CAPS:
case HEADER_CPU_DOMAIN_INFO:
case HEADER_CLN_SIZE:
case HEADER_MEMORY_RANGES:
return true;
/* Information that can be updated */
case HEADER_BUILD_ID:
@ -2880,6 +2881,9 @@ int cmd_inject(int argc, const char **argv)
goto out_close_output;
}
if (inject.aslr)
aslr_tool__register_session(tool, inject.session);
if (zstd_init(&(inject.session->zstd_data), 0) < 0)
pr_warning("Decompression initialization failed.\n");

View File

@ -1870,8 +1870,7 @@ static bool slab_legacy_tp_is_exposed(void)
* means the tool is running on an old kernel, we need to
* rollback to support these legacy tracepoints.
*/
return IS_ERR(trace_event__tp_format("kmem", "kmalloc_node")) ?
false : true;
return trace_event__tp_format("kmem", "kmalloc_node");
}
static int __cmd_record(int argc, const char **argv)

View File

@ -27,6 +27,7 @@
#include "util/kvm-stat.h"
#include "util/util.h"
#include "ui/browsers/hists.h"
#include "ui/keysyms.h"
#include "ui/progress.h"
#include "ui/ui.h"
#include "util/string2.h"
@ -1043,7 +1044,7 @@ static void show_timeofday(void)
gettimeofday(&tv, NULL);
if (localtime_r(&tv.tv_sec, &ltime)) {
strftime(date, sizeof(date), "%H:%M:%S", &ltime);
pr_info("%s.%06ld", date, tv.tv_usec);
pr_info("%s.%06ld", date, (long)tv.tv_usec);
} else
pr_info("00:00:00.000000");

View File

@ -24,8 +24,10 @@
#include <subcmd/parse-options.h>
#include <linux/zalloc.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
/**
* struct print_state - State and configuration passed to the default_print
@ -325,7 +327,7 @@ static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, ..
case 'S': {
const char *s = va_arg(args, const char*);
for (size_t s_pos = 0; s_pos < strlen(s); s_pos++) {
for (size_t s_pos = 0; s[s_pos] != '\0'; s_pos++) {
switch (s[s_pos]) {
case '\n':
strbuf_addstr(buf, "\\n");
@ -538,6 +540,31 @@ static bool default_skip_duplicate_pmus(void *ps)
return !print_state->long_desc;
}
/*
* Launch the interactive textual based ilist python script via 'perf script'
* that finds the script and sets up the python environment. Arguments are
* passed to the script.
*/
static int list__tui(int argc, const char **argv)
{
const char **script_argv;
int script_argc = 0, ret;
script_argv = calloc(argc + 4, sizeof(*script_argv));
if (!script_argv)
return -ENOMEM;
script_argv[script_argc++] = "script";
script_argv[script_argc++] = "ilist";
script_argv[script_argc++] = "--";
for (int i = 0; i < argc; i++)
script_argv[script_argc++] = argv[i];
ret = cmd_script(script_argc, script_argv);
free(script_argv);
return ret;
}
int cmd_list(int argc, const char **argv)
{
int i, ret = 0;
@ -562,6 +589,7 @@ int cmd_list(int argc, const char **argv)
const char *unit_name = NULL;
const char *output_path = NULL;
bool json = false;
bool use_tui = false;
struct option list_options[] = {
OPT_BOOLEAN(0, "raw-dump", &default_ps.name_only, "Dump raw events"),
OPT_BOOLEAN('j', "json", &json, "JSON encode events and metrics"),
@ -578,6 +606,8 @@ int cmd_list(int argc, const char **argv)
"Limit PMU or metric printing to the given PMU (e.g. cpu, core or atom)."),
OPT_STRING(0, "unit", &unit_name, "PMU name",
"Limit PMU or metric printing to the specified PMU."),
OPT_BOOLEAN(0, "tui", &use_tui,
"Interactively browse and count events and metrics with ilist"),
OPT_INCR(0, "debug", &verbose,
"Enable debugging output"),
OPT_END()
@ -588,6 +618,7 @@ int cmd_list(int argc, const char **argv)
#else
"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
#endif
"perf list --tui [-- <ilist options>]",
NULL
};
@ -598,6 +629,9 @@ int cmd_list(int argc, const char **argv)
argc = parse_options(argc, argv, list_options, list_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (use_tui)
return list__tui(argc, argv);
if (json)
ps = &json_ps.common;

View File

@ -975,6 +975,7 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
struct machine *machine = &session->machines.host;
struct map *kmap;
struct symbol *sym;
u64 *callstack = NULL;
ret = get_key_by_aggr_mode(&key, addr, sample);
if (ret < 0)
@ -1010,33 +1011,6 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
}
}
ls = lock_stat_find(key);
if (!ls) {
char buf[128];
const char *name = "";
switch (aggr_mode) {
case LOCK_AGGR_ADDR:
sym = machine__find_kernel_symbol(machine, key, &kmap);
if (sym)
name = sym->name;
break;
case LOCK_AGGR_CALLER:
name = buf;
if (lock_contention_caller(sample, buf, sizeof(buf)) < 0)
name = "Unknown";
break;
case LOCK_AGGR_CGROUP:
case LOCK_AGGR_TASK:
default:
break;
}
ls = lock_stat_findnew(key, name, flags);
if (!ls)
return -ENOMEM;
}
if (filters.nr_types) {
bool found = false;
@ -1066,7 +1040,7 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
}
if (needs_callstack()) {
u64 *callstack = get_callstack(sample, max_stack_depth);
callstack = get_callstack(sample, max_stack_depth);
if (callstack == NULL)
return 0;
@ -1074,7 +1048,38 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
free(callstack);
return 0;
}
}
ls = lock_stat_find(key);
if (!ls) {
char buf[128];
const char *name = "";
switch (aggr_mode) {
case LOCK_AGGR_ADDR:
sym = machine__find_kernel_symbol(machine, key, &kmap);
if (sym)
name = sym->name;
break;
case LOCK_AGGR_CALLER:
name = buf;
if (lock_contention_caller(sample, buf, sizeof(buf)) < 0)
name = "Unknown";
break;
case LOCK_AGGR_CGROUP:
case LOCK_AGGR_TASK:
default:
break;
}
ls = lock_stat_findnew(key, name, flags);
if (!ls) {
free(callstack);
return -ENOMEM;
}
}
if (callstack) {
if (ls->callstack == NULL)
ls->callstack = callstack;
else

View File

@ -99,8 +99,8 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem,
argc = parse_options(argc, argv, options, record_usage,
PARSE_OPT_KEEP_UNKNOWN);
/* Max number of arguments multiplied by number of PMUs that can support them. */
rec_argc = argc + 9 * (perf_pmu__mem_events_num_mem_pmus(pmu) + 1);
/* Max number of arguments per PMU plus the fixed ones added below. */
rec_argc = argc + 8 + 9 * (perf_pmu__mem_events_num_mem_pmus(pmu) + 1);
if (mem->cpu_list)
rec_argc += 2;
@ -135,6 +135,9 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem,
rec_argv[i++] = "-d";
/* Cross-CPU contention keys on sample->cpu, -1 without PERF_SAMPLE_CPU. */
rec_argv[i++] = "--sample-cpu";
if (mem->phys_addr)
rec_argv[i++] = "--phys-data";

View File

@ -1169,6 +1169,21 @@ static int record__update_evlist_pollfd_from_thread(struct record *rec,
int e_pos = rec->index_map[i].evlist_pollfd_index;
int t_pos = rec->index_map[i].thread_pollfd_index;
if (e_entries[e_pos].fd == -1 || e_entries[e_pos].events == 0) {
/*
* If the control file descriptor was closed, then evlist__ctlfd_process()
* will have called evlist__finalize_ctlfd() on the PREVIOUS loop iteration
* to cleanly set the core evlist's e_entries[e_pos].fd to -1.
*
* Since nonfilterable items are skipped by fdarray__filter(), the
* thread's local t_entries[t_pos] retains its original state.
* We must explicitly propagate the finalized -1 state to t_entries
* BEFORE evaluating the strict equivalence check below.
*/
t_entries[t_pos].fd = -1;
t_entries[t_pos].events = 0;
}
if (e_entries[e_pos].fd != t_entries[t_pos].fd ||
e_entries[e_pos].events != t_entries[t_pos].events) {
pr_err("Thread and evlist pollfd index mismatch\n");

View File

@ -51,6 +51,7 @@
#include "util/units.h"
#include "util/unwind.h"
#include "util/util.h" // perf_tip()
#include "ui/keysyms.h"
#include "ui/ui.h"
#include "ui/progress.h"
#include "util/block-info.h"
@ -82,10 +83,12 @@ struct report {
#ifdef HAVE_SLANG_SUPPORT
bool use_tui;
#endif
#ifdef HAVE_GTK2_SUPPORT
#ifdef HAVE_GTK4_SUPPORT
bool use_gtk;
#endif
bool use_stdio;
bool progress;
bool progress_set;
bool show_full_info;
bool show_threads;
bool inverted_callchain;
@ -1113,6 +1116,23 @@ static int __cmd_report(struct report *rep)
evlist__for_each_entry(session->evlist, pos)
rep->nr_entries += evsel__hists(pos)->nr_entries;
if (symbol_conf.hybrid_merge) {
struct perf_env *env = perf_session__env(session);
if (evlist__can_merge_hybrid(session->evlist, env)) {
evlist__merge_hybrid(session->evlist, env);
evlist__merge_hists_hybrid(session->evlist, false);
} else if (symbol_conf.hybrid_merge_set) {
/*
* Only an explicit --hybrid-merge warns. A
* core.hybrid-merge default is silent, as most
* machines aren't hybrid and there is nothing the
* user needs to do about it.
*/
ui__warning("--hybrid-merge: no events to merge across core PMUs\n");
}
}
if (use_browser == 0) {
if (verbose > 3)
perf_session__fprintf(session, stdout);
@ -1359,11 +1379,15 @@ int cmd_report(int argc, const char **argv)
#ifdef HAVE_SLANG_SUPPORT
OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
#endif
#ifdef HAVE_GTK2_SUPPORT
OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
#ifdef HAVE_GTK4_SUPPORT
OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK4 interface"),
#endif
OPT_BOOLEAN(0, "stdio", &report.use_stdio,
"Use the stdio interface"),
OPT_BOOLEAN(0, "weights", &symbol_conf.annotate_weight,
"Show or hide weight columns in annotation. Default show if non-zero."),
OPT_BOOLEAN_SET(0, "progress", &report.progress, &report.progress_set,
"Show progress while processing the perf.data file"),
OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
OPT_BOOLEAN(0, "header-only", &report.header_only,
"Show only data header."),
@ -1446,6 +1470,9 @@ int cmd_report(int argc, const char **argv)
parse_branch_mode),
OPT_BOOLEAN(0, "branch-history", &branch_call_mode,
"add last branch records to call history"),
OPT_BOOLEAN_SET(0, "hybrid-merge", &symbol_conf.hybrid_merge,
&symbol_conf.hybrid_merge_set,
"merge the same event across hybrid core PMUs"),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_STRING(0, "addr2line", &addr2line_path, "path",
@ -1525,6 +1552,7 @@ int cmd_report(int argc, const char **argv)
* reference exited threads.
*/
symbol_conf.keep_exited_threads = true;
symbol_conf.annotate_weight = true;
annotation_options__init();
@ -1544,6 +1572,17 @@ int cmd_report(int argc, const char **argv)
report.symbol_filter_str = argv[0];
}
if (symbol_conf.report_hierarchy && symbol_conf.hybrid_merge) {
if (symbol_conf.hybrid_merge_set) {
pr_err("Error: --hierarchy and --hybrid-merge are mutually exclusive.\n");
ret = -EINVAL;
goto exit;
}
/* A config file default shouldn't fail an explicit option. */
pr_warning("core.hybrid-merge ignored: --hierarchy cannot display merged hybrid events\n");
symbol_conf.hybrid_merge = false;
}
if (disassembler_style) {
annotate_opts.disassembler_style = strdup(disassembler_style);
if (!annotate_opts.disassembler_style)
@ -1710,7 +1749,7 @@ int cmd_report(int argc, const char **argv)
else if (report.use_tui)
use_browser = 1;
#endif
#ifdef HAVE_GTK2_SUPPORT
#ifdef HAVE_GTK4_SUPPORT
else if (report.use_gtk)
use_browser = 2;
#endif
@ -1755,6 +1794,11 @@ int cmd_report(int argc, const char **argv)
else
use_browser = 0;
if (report.progress_set && !report.progress)
ui_progress__noop_init();
else if (report.progress && !quiet && use_browser == 0)
stdio_progress__init();
if (report.data_type && use_browser == 1) {
symbol_conf.annotate_data_member = true;
symbol_conf.annotate_data_sample = true;

View File

@ -4137,7 +4137,7 @@ static int disable_sched_schedstat(void)
}
/* perf.data or any other output file name used by stats subcommand (only). */
const char *output_name;
static const char *output_name;
static int perf_sched__schedstat_record(struct perf_sched *sched,
int argc, const char **argv)
@ -4281,18 +4281,18 @@ struct schedstat_cpu {
};
static struct list_head cpu_head = LIST_HEAD_INIT(cpu_head);
static struct schedstat_cpu *cpu_second_pass;
static struct schedstat_domain *domain_second_pass;
static struct list_head *cpu_second_pass;
static struct list_head *domain_second_pass;
static u64 schedstat_timestamp;
static bool after_workload_flag;
static bool verbose_field;
static void free_schedstat(struct list_head *head);
static void store_schedstat_cpu_diff(struct schedstat_cpu *after_workload)
static void store_schedstat_cpu_diff(struct perf_record_schedstat_cpu *before,
struct perf_record_schedstat_cpu *after)
{
struct perf_record_schedstat_cpu *before = cpu_second_pass->cpu_data;
struct perf_record_schedstat_cpu *after = after_workload->cpu_data;
__u16 version = after_workload->cpu_data->version;
__u16 version = after->version;
#define CPU_FIELD(_type, _name, _desc, _format, _is_pct, _pct_of, _ver) \
(before->_ver._name = after->_ver._name - before->_ver._name)
@ -4308,11 +4308,10 @@ static void store_schedstat_cpu_diff(struct schedstat_cpu *after_workload)
#undef CPU_FIELD
}
static void store_schedstat_domain_diff(struct schedstat_domain *after_workload)
static void store_schedstat_domain_diff(struct perf_record_schedstat_domain *before,
struct perf_record_schedstat_domain *after)
{
struct perf_record_schedstat_domain *before = domain_second_pass->domain_data;
struct perf_record_schedstat_domain *after = after_workload->domain_data;
__u16 version = after_workload->domain_data->version;
__u16 version = after->version;
#define DOMAIN_FIELD(_type, _name, _desc, _format, _is_jiffies, _ver) \
(before->_ver._name = after->_ver._name - before->_ver._name)
@ -4814,12 +4813,35 @@ static int show_schedstat_data(struct list_head *head1, struct cpu_domain_map **
* other after completion of the workload. The above linked list stores the diff of the cpu and
* domain statistics.
*/
static int schedstat_snapshot_error(void)
{
pr_err("Incompatible or incomplete schedstat snapshots\n");
return -EINVAL;
}
static bool schedstat_domains_complete(void)
{
struct schedstat_cpu *cpu;
if (!domain_second_pass)
return true;
cpu = list_entry(cpu_second_pass, struct schedstat_cpu, cpu_list);
return domain_second_pass == &cpu->domain_head;
}
static int schedstat_snapshots_complete(void)
{
if (!after_workload_flag || !cpu_second_pass ||
cpu_second_pass->next != &cpu_head || !schedstat_domains_complete())
return schedstat_snapshot_error();
return 0;
}
static int perf_sched__process_schedstat(const struct perf_tool *tool __maybe_unused,
struct perf_session *session __maybe_unused,
union perf_event *event)
{
struct perf_cpu this_cpu;
static __u32 initial_cpu;
switch (event->header.type) {
case PERF_RECORD_SCHEDSTAT_CPU:
@ -4836,63 +4858,91 @@ static int perf_sched__process_schedstat(const struct perf_tool *tool __maybe_un
return 0;
if (event->header.type == PERF_RECORD_SCHEDSTAT_CPU) {
struct schedstat_cpu *temp = zalloc(sizeof(*temp));
struct perf_record_schedstat_cpu *data = &event->schedstat_cpu;
struct schedstat_cpu *cpu;
if (!temp)
return -ENOMEM;
temp->cpu_data = zalloc(sizeof(*temp->cpu_data));
if (!temp->cpu_data)
return -ENOMEM;
memcpy(temp->cpu_data, &event->schedstat_cpu, sizeof(*temp->cpu_data));
if (!list_empty(&cpu_head) && temp->cpu_data->cpu == initial_cpu)
after_workload_flag = true;
if (!after_workload_flag) {
if (list_empty(&cpu_head))
initial_cpu = temp->cpu_data->cpu;
list_add_tail(&temp->cpu_list, &cpu_head);
INIT_LIST_HEAD(&temp->domain_head);
} else {
if (temp->cpu_data->cpu == initial_cpu) {
cpu_second_pass = list_first_entry(&cpu_head, struct schedstat_cpu,
cpu_list);
cpu_second_pass->cpu_data->timestamp =
temp->cpu_data->timestamp - cpu_second_pass->cpu_data->timestamp;
} else {
cpu_second_pass = list_next_entry(cpu_second_pass, cpu_list);
if (list_empty(&cpu_head)) {
after_workload_flag = false;
cpu_second_pass = &cpu_head;
domain_second_pass = NULL;
schedstat_timestamp = data->timestamp;
} else if (!after_workload_flag) {
cpu = list_last_entry(&cpu_head, struct schedstat_cpu, cpu_list);
/* Snapshots share a timestamp and list CPUs in increasing order. */
if (data->timestamp != schedstat_timestamp ||
data->cpu <= cpu->cpu_data->cpu) {
after_workload_flag = true;
schedstat_timestamp = data->timestamp;
}
domain_second_pass = list_first_entry(&cpu_second_pass->domain_head,
struct schedstat_domain, domain_list);
store_schedstat_cpu_diff(temp);
free(temp->cpu_data);
free(temp);
}
} else if (event->header.type == PERF_RECORD_SCHEDSTAT_DOMAIN) {
struct schedstat_cpu *cpu_tail;
struct schedstat_domain *temp = zalloc(sizeof(*temp));
if (!temp)
return -ENOMEM;
temp->domain_data = zalloc(sizeof(*temp->domain_data));
if (!temp->domain_data)
return -ENOMEM;
memcpy(temp->domain_data, &event->schedstat_domain, sizeof(*temp->domain_data));
if (!after_workload_flag) {
cpu_tail = list_last_entry(&cpu_head, struct schedstat_cpu, cpu_list);
list_add_tail(&temp->domain_list, &cpu_tail->domain_head);
} else {
store_schedstat_domain_diff(temp);
domain_second_pass = list_next_entry(domain_second_pass, domain_list);
free(temp->domain_data);
free(temp);
if (after_workload_flag) {
if (data->timestamp != schedstat_timestamp || !schedstat_domains_complete())
return schedstat_snapshot_error();
cpu_second_pass = cpu_second_pass->next;
if (cpu_second_pass == &cpu_head)
return schedstat_snapshot_error();
cpu = list_entry(cpu_second_pass, struct schedstat_cpu, cpu_list);
if (data->cpu != cpu->cpu_data->cpu ||
data->version != cpu->cpu_data->version ||
data->timestamp < cpu->cpu_data->timestamp)
return schedstat_snapshot_error();
cpu->cpu_data->timestamp = data->timestamp - cpu->cpu_data->timestamp;
store_schedstat_cpu_diff(cpu->cpu_data, data);
domain_second_pass = cpu->domain_head.next;
return 0;
}
cpu = zalloc(sizeof(*cpu));
if (!cpu)
return -ENOMEM;
cpu->cpu_data = memdup(data, sizeof(*data));
if (!cpu->cpu_data) {
free(cpu);
return -ENOMEM;
}
INIT_LIST_HEAD(&cpu->domain_head);
list_add_tail(&cpu->cpu_list, &cpu_head);
} else {
struct perf_record_schedstat_domain *data = &event->schedstat_domain;
struct schedstat_domain *domain;
struct schedstat_cpu *cpu;
if (list_empty(&cpu_head) || data->timestamp != schedstat_timestamp)
return schedstat_snapshot_error();
if (after_workload_flag) {
cpu = list_entry(cpu_second_pass, struct schedstat_cpu, cpu_list);
if (domain_second_pass == &cpu->domain_head)
return schedstat_snapshot_error();
domain = list_entry(domain_second_pass, struct schedstat_domain,
domain_list);
if (data->cpu != domain->domain_data->cpu ||
data->domain != domain->domain_data->domain ||
data->version != domain->domain_data->version)
return schedstat_snapshot_error();
store_schedstat_domain_diff(domain->domain_data, data);
domain_second_pass = domain_second_pass->next;
return 0;
}
cpu = list_last_entry(&cpu_head, struct schedstat_cpu, cpu_list);
if (data->cpu != cpu->cpu_data->cpu || data->version != cpu->cpu_data->version)
return schedstat_snapshot_error();
if (!list_empty(&cpu->domain_head)) {
domain = list_last_entry(&cpu->domain_head, struct schedstat_domain,
domain_list);
if (data->domain <= domain->domain_data->domain)
return schedstat_snapshot_error();
}
domain = zalloc(sizeof(*domain));
if (!domain)
return -ENOMEM;
domain->domain_data = memdup(data, sizeof(*data));
if (!domain->domain_data) {
free(domain);
return -ENOMEM;
}
list_add_tail(&domain->domain_list, &cpu->domain_head);
}
return 0;
@ -4947,6 +4997,8 @@ static int perf_sched__schedstat_report(struct perf_sched *sched)
user_requested_cpus = evlist__core(session->evlist)->user_requested_cpus;
err = perf_session__process_events(session);
if (!err)
err = schedstat_snapshots_complete();
if (!err) {
setup_pager();
@ -4976,7 +5028,7 @@ static int perf_sched__schedstat_diff(struct perf_sched *sched,
struct list_head cpu_head_ses0, cpu_head_ses1;
struct perf_session *session[2];
struct perf_data data[2] = {0};
int ret = 0, err = 0;
int ret = 0;
static const char *defaults[] = {
"perf.data.old",
"perf.data",
@ -5009,8 +5061,10 @@ static int perf_sched__schedstat_diff(struct perf_sched *sched,
goto out_delete_ses0;
}
err = perf_session__process_events(session[0]);
if (err) {
ret = perf_session__process_events(session[0]);
if (!ret)
ret = schedstat_snapshots_complete();
if (ret) {
free_schedstat(&cpu_head);
goto out_delete_ses0;
}
@ -5028,8 +5082,10 @@ static int perf_sched__schedstat_diff(struct perf_sched *sched,
goto out_delete_ses1;
}
err = perf_session__process_events(session[1]);
if (err) {
ret = perf_session__process_events(session[1]);
if (!ret)
ret = schedstat_snapshots_complete();
if (ret) {
free_schedstat(&cpu_head);
goto out_delete_ses1;
}
@ -5152,6 +5208,9 @@ static int perf_sched__schedstat_live(struct perf_sched *sched,
user_requested_cpus);
if (err)
goto out;
err = schedstat_snapshots_complete();
if (err)
goto out;
setup_pager();
@ -5182,8 +5241,7 @@ static bool schedstat_events_exposed(void)
* Select "sched:sched_stat_wait" event to check
* whether schedstat tracepoints are exposed.
*/
return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ?
false : true;
return trace_event__tp_format("sched", "sched_stat_wait");
}
static int __cmd_record(int argc, const char **argv)
@ -5240,7 +5298,7 @@ static int __cmd_record(int argc, const char **argv)
rec_argv[i++] = strdup("-e");
waking_event = trace_event__tp_format("sched", "sched_waking");
if (!IS_ERR(waking_event))
if (waking_event)
rec_argv[i++] = strdup("sched:sched_waking");
else
rec_argv[i++] = strdup("sched:sched_wakeup");

File diff suppressed because it is too large Load Diff

View File

@ -777,7 +777,6 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
int interval = stat_config.interval;
int times = stat_config.times;
int timeout = stat_config.timeout;
char msg[BUFSIZ];
unsigned long long t0, t1;
struct evsel *counter;
size_t l;
@ -908,6 +907,9 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
}
}
if (!has_supported_counters && !stat_config.null_run) {
char msg[BUFSIZ];
msg[0] = '\0';
if (open_err) {
evsel__open_strerror(evlist__first(evsel_list), &target, open_err,
msg, sizeof(msg));

View File

@ -10,6 +10,7 @@
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include "builtin.h"
#include "util/color.h"
@ -68,6 +69,7 @@ struct timechart {
with_backtrace,
topology;
bool force;
bool use_tui;
/* IO related settings */
bool io_only,
skip_eagain;
@ -351,10 +353,6 @@ static int process_exit_event(const struct perf_tool *tool,
return 0;
}
#ifdef SUPPORT_OLD_POWER_EVENTS
static int use_old_power_events;
#endif
static void c_state_start(int cpu, u64 timestamp, int state)
{
cpus_cstate_start_times[cpu] = timestamp;
@ -1760,6 +1758,41 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
return ret;
}
/*
* Launch the interactive textual based python script via 'perf script' that
* finds the script, sets up the python environment and passes the global
* input_name (set by -i) to the script as '-i <input_name>'.
*/
static int timechart__tui(struct timechart *tchart)
{
struct process_filter *filt;
const char **script_argv;
int script_argc = 0, nr_args = 5, ret;
for (filt = process_filter; filt; filt = filt->next)
nr_args += 2;
script_argv = calloc(nr_args + 1, sizeof(*script_argv));
if (!script_argv)
return -ENOMEM;
script_argv[script_argc++] = "script";
script_argv[script_argc++] = "ttimechart";
script_argv[script_argc++] = "--";
if (tchart->power_only)
script_argv[script_argc++] = "-P";
if (tchart->tasks_only)
script_argv[script_argc++] = "-T";
for (filt = process_filter; filt; filt = filt->next) {
script_argv[script_argc++] = "-p";
script_argv[script_argc++] = filt->name;
}
ret = cmd_script(script_argc, script_argv);
free(script_argv);
return ret;
}
static int timechart__io_record(int argc, const char **argv, const char *output_data)
{
unsigned int rec_argc, i;
@ -1943,7 +1976,6 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
#ifdef SUPPORT_OLD_POWER_EVENTS
if (!is_valid_tracepoint("power:cpu_idle") &&
is_valid_tracepoint("power:power_start")) {
use_old_power_events = 1;
power_args_nr = 0;
} else {
old_power_args_nr = 0;
@ -2084,6 +2116,8 @@ int cmd_timechart(int argc, const char **argv)
"merge events that are merge-dist us apart",
parse_time),
OPT_BOOLEAN('f', "force", &tchart.force, "don't complain, do it"),
OPT_BOOLEAN(0, "tui", &tchart.use_tui,
"interactive terminal timechart using the ttimechart python script"),
OPT_PARENT(timechart_common_options),
};
const char * const timechart_subcommands[] = { "record", NULL };
@ -2151,6 +2185,11 @@ int cmd_timechart(int argc, const char **argv)
} else if (argc)
usage_with_options(timechart_usage, timechart_options);
if (tchart.use_tui) {
ret = timechart__tui(&tchart);
goto out;
}
setup_pager();
ret = __cmd_timechart(&tchart, output_name);

View File

@ -51,6 +51,7 @@
#include "util/intlist.h"
#include "util/parse-branch-options.h"
#include "arch/common.h"
#include "ui/keysyms.h"
#include "ui/ui.h"
#include "util/debug.h"
@ -1313,9 +1314,11 @@ static int __cmd_top(struct perf_top *top)
}
/*
* Use global stat_config that is zero meaning aggr_mode is AGGR_NONE
* and hybrid_merge is false.
* Use global stat_config that is zero meaning aggr_mode is AGGR_NONE.
* Merging affects the event names as merged events share a name, all
* other stat_config behavior is unwanted here.
*/
stat_config.hybrid_merge = symbol_conf.hybrid_merge;
evlist__uniquify_evsel_names(top->evlist, &stat_config);
ret = perf_top__start_counters(top);
if (ret)
@ -1335,6 +1338,21 @@ static int __cmd_top(struct perf_top *top)
if (!target__none(&opts->target))
evlist__enable(top->evlist);
if (symbol_conf.hybrid_merge) {
if (evlist__can_merge_hybrid(top->evlist, /*env=*/NULL)) {
evlist__merge_hybrid(top->evlist, /*env=*/NULL);
evlist__merge_hists_hybrid(top->evlist, false);
} else if (symbol_conf.hybrid_merge_set) {
/*
* Only an explicit --hybrid-merge warns. A
* core.hybrid-merge default is silent, as most
* machines aren't hybrid and there is nothing the
* user needs to do about it.
*/
ui__warning("--hybrid-merge: no events to merge across core PMUs\n");
}
}
ret = -1;
if (pthread_create(&thread_process, NULL, process_thread, top)) {
ui__error("Could not create process thread.\n");
@ -1490,9 +1508,14 @@ int cmd_top(int argc, const char **argv)
OPT_CALLBACK('e', "event", &parse_events_option_args, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
OPT_BOOLEAN_SET(0, "hybrid-merge", &symbol_conf.hybrid_merge,
&symbol_conf.hybrid_merge_set,
"merge the same event across hybrid core PMUs"),
OPT_CALLBACK(0, "filter", &top.evlist, "filter",
"event filter", parse_filter),
OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
OPT_BOOLEAN('W', "weight", &opts->sample_weight,
"sample by weight (on special events only)"),
OPT_STRING('p', "pid", &target->pid, "pid",
"profile events on existing process id"),
OPT_STRING('t', "tid", &target->tid, "tid",
@ -1676,6 +1699,17 @@ int cmd_top(int argc, const char **argv)
if (argc)
usage_with_options(top_usage, options);
if (symbol_conf.report_hierarchy && symbol_conf.hybrid_merge) {
if (symbol_conf.hybrid_merge_set) {
pr_err("Error: --hierarchy and --hybrid-merge are mutually exclusive.\n");
status = -EINVAL;
goto out_put_evlist;
}
/* A config file default shouldn't fail an explicit option. */
pr_warning("core.hybrid-merge ignored: --hierarchy cannot display merged hybrid events\n");
symbol_conf.hybrid_merge = false;
}
if (disassembler_style) {
annotate_opts.disassembler_style = strdup(disassembler_style);
if (!annotate_opts.disassembler_style) {

File diff suppressed because it is too large Load Diff

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