diff options
Diffstat (limited to 'tools')
328 files changed, 6951 insertions, 3980 deletions
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 5171b9c7ca3e..0652d3eed9bd 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -231,6 +231,8 @@ #define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */ #define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */ #define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */ +#define X86_FEATURE_VMCALL ( 8*32+18) /* "" Hypervisor supports the VMCALL instruction */ +#define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ @@ -354,6 +356,7 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ +#define X86_FEATURE_AVX512_VP2INTERSECT (18*32+ 8) /* AVX-512 Intersect for D/Q */ #define X86_FEATURE_MD_CLEAR (18*32+10) /* VERW clears CPU buffers */ #define X86_FEATURE_TSX_FORCE_ABORT (18*32+13) /* "" TSX_FORCE_ABORT */ #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ diff --git a/tools/arch/x86/include/uapi/asm/unistd.h b/tools/arch/x86/include/uapi/asm/unistd.h index 30d7d04d72d6..196fdd02b8b1 100644 --- a/tools/arch/x86/include/uapi/asm/unistd.h +++ b/tools/arch/x86/include/uapi/asm/unistd.h @@ -3,7 +3,7 @@ #define _UAPI_ASM_X86_UNISTD_H /* x32 syscall flag bit */ -#define __X32_SYSCALL_BIT 0x40000000 +#define __X32_SYSCALL_BIT 0x40000000UL #ifndef __KERNEL__ # ifdef __i386__ diff --git a/tools/hv/Build b/tools/hv/Build new file mode 100644 index 000000000000..6cf51fa4b306 --- /dev/null +++ b/tools/hv/Build @@ -0,0 +1,3 @@ +hv_kvp_daemon-y += hv_kvp_daemon.o +hv_vss_daemon-y += hv_vss_daemon.o +hv_fcopy_daemon-y += hv_fcopy_daemon.o diff --git a/tools/hv/Makefile b/tools/hv/Makefile index 5db5e62cebda..b57143d9459c 100644 --- a/tools/hv/Makefile +++ b/tools/hv/Makefile @@ -1,28 +1,55 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for Hyper-V tools - -WARNINGS = -Wall -Wextra -CFLAGS = $(WARNINGS) -g $(shell getconf LFS_CFLAGS) - -CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include +include ../scripts/Makefile.include sbindir ?= /usr/sbin libexecdir ?= /usr/libexec sharedstatedir ?= /var/lib -ALL_PROGRAMS := hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(CURDIR))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +endif + +# Do not use make's built-in rules +# (this improves performance and avoids hard-to-debug behaviour); +MAKEFLAGS += -r + +override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include + +ALL_TARGETS := hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon +ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) ALL_SCRIPTS := hv_get_dhcp_info.sh hv_get_dns_info.sh hv_set_ifconfig.sh all: $(ALL_PROGRAMS) -%: %.c - $(CC) $(CFLAGS) -o $@ $^ +export srctree OUTPUT CC LD CFLAGS +include $(srctree)/tools/build/Makefile.include + +HV_KVP_DAEMON_IN := $(OUTPUT)hv_kvp_daemon-in.o +$(HV_KVP_DAEMON_IN): FORCE + $(Q)$(MAKE) $(build)=hv_kvp_daemon +$(OUTPUT)hv_kvp_daemon: $(HV_KVP_DAEMON_IN) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +HV_VSS_DAEMON_IN := $(OUTPUT)hv_vss_daemon-in.o +$(HV_VSS_DAEMON_IN): FORCE + $(Q)$(MAKE) $(build)=hv_vss_daemon +$(OUTPUT)hv_vss_daemon: $(HV_VSS_DAEMON_IN) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + +HV_FCOPY_DAEMON_IN := $(OUTPUT)hv_fcopy_daemon-in.o +$(HV_FCOPY_DAEMON_IN): FORCE + $(Q)$(MAKE) $(build)=hv_fcopy_daemon +$(OUTPUT)hv_fcopy_daemon: $(HV_FCOPY_DAEMON_IN) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ clean: - $(RM) hv_kvp_daemon hv_vss_daemon hv_fcopy_daemon + rm -f $(ALL_PROGRAMS) + find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete -install: all +install: $(ALL_PROGRAMS) install -d -m 755 $(DESTDIR)$(sbindir); \ install -d -m 755 $(DESTDIR)$(libexecdir)/hypervkvpd; \ install -d -m 755 $(DESTDIR)$(sharedstatedir); \ @@ -33,3 +60,7 @@ install: all for script in $(ALL_SCRIPTS); do \ install $$script -m 755 $(DESTDIR)$(libexecdir)/hypervkvpd/$${script%.sh}; \ done + +FORCE: + +.PHONY: all install clean FORCE prepare diff --git a/tools/include/asm/bug.h b/tools/include/asm/bug.h index bbd75ac8b202..550223f0a6e6 100644 --- a/tools/include/asm/bug.h +++ b/tools/include/asm/bug.h @@ -3,6 +3,7 @@ #define _TOOLS_ASM_BUG_H #include <linux/compiler.h> +#include <stdio.h> #define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) diff --git a/tools/include/linux/rbtree.h b/tools/include/linux/rbtree.h index d83763a5327c..e03b1ea23e0e 100644 --- a/tools/include/linux/rbtree.h +++ b/tools/include/linux/rbtree.h @@ -31,25 +31,9 @@ struct rb_root { struct rb_node *rb_node; }; -/* - * Leftmost-cached rbtrees. - * - * We do not cache the rightmost node based on footprint - * size vs number of potential users that could benefit - * from O(1) rb_last(). Just not worth it, users that want - * this feature can always implement the logic explicitly. - * Furthermore, users that want to cache both pointers may - * find it a bit asymmetric, but that's ok. - */ -struct rb_root_cached { - struct rb_root rb_root; - struct rb_node *rb_leftmost; -}; - #define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) #define RB_ROOT (struct rb_root) { NULL, } -#define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL } #define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL) @@ -71,12 +55,6 @@ extern struct rb_node *rb_prev(const struct rb_node *); extern struct rb_node *rb_first(const struct rb_root *); extern struct rb_node *rb_last(const struct rb_root *); -extern void rb_insert_color_cached(struct rb_node *, - struct rb_root_cached *, bool); -extern void rb_erase_cached(struct rb_node *node, struct rb_root_cached *); -/* Same as rb_first(), but O(1) */ -#define rb_first_cached(root) (root)->rb_leftmost - /* Postorder iteration - always visit the parent after its children */ extern struct rb_node *rb_first_postorder(const struct rb_root *); extern struct rb_node *rb_next_postorder(const struct rb_node *); @@ -84,8 +62,6 @@ extern struct rb_node *rb_next_postorder(const struct rb_node *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); -extern void rb_replace_node_cached(struct rb_node *victim, struct rb_node *new, - struct rb_root_cached *root); static inline void rb_link_node(struct rb_node *node, struct rb_node *parent, struct rb_node **rb_link) @@ -129,4 +105,51 @@ static inline void rb_erase_init(struct rb_node *n, struct rb_root *root) rb_erase(n, root); RB_CLEAR_NODE(n); } + +/* + * Leftmost-cached rbtrees. + * + * We do not cache the rightmost node based on footprint + * size vs number of potential users that could benefit + * from O(1) rb_last(). Just not worth it, users that want + * this feature can always implement the logic explicitly. + * Furthermore, users that want to cache both pointers may + * find it a bit asymmetric, but that's ok. + */ +struct rb_root_cached { + struct rb_root rb_root; + struct rb_node *rb_leftmost; +}; + +#define RB_ROOT_CACHED (struct rb_root_cached) { {NULL, }, NULL } + +/* Same as rb_first(), but O(1) */ +#define rb_first_cached(root) (root)->rb_leftmost + +static inline void rb_insert_color_cached(struct rb_node *node, + struct rb_root_cached *root, + bool leftmost) +{ + if (leftmost) + root->rb_leftmost = node; + rb_insert_color(node, &root->rb_root); +} + +static inline void rb_erase_cached(struct rb_node *node, + struct rb_root_cached *root) +{ + if (root->rb_leftmost == node) + root->rb_leftmost = rb_next(node); + rb_erase(node, &root->rb_root); +} + +static inline void rb_replace_node_cached(struct rb_node *victim, + struct rb_node *new, + struct rb_root_cached *root) +{ + if (root->rb_leftmost == victim) + root->rb_leftmost = new; + rb_replace_node(victim, new, &root->rb_root); +} + #endif /* __TOOLS_LINUX_PERF_RBTREE_H */ diff --git a/tools/include/linux/rbtree_augmented.h b/tools/include/linux/rbtree_augmented.h index ddd01006ece5..381aa948610d 100644 --- a/tools/include/linux/rbtree_augmented.h +++ b/tools/include/linux/rbtree_augmented.h @@ -32,17 +32,16 @@ struct rb_augment_callbacks { void (*rotate)(struct rb_node *old, struct rb_node *new); }; -extern void __rb_insert_augmented(struct rb_node *node, - struct rb_root *root, - bool newleft, struct rb_node **leftmost, +extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); + /* * Fixup the rbtree and update the augmented information when rebalancing. * * On insertion, the user must update the augmented information on the path * leading to the inserted node, then call rb_link_node() as usual and - * rb_augment_inserted() instead of the usual rb_insert_color() call. - * If rb_augment_inserted() rebalances the rbtree, it will callback into + * rb_insert_augmented() instead of the usual rb_insert_color() call. + * If rb_insert_augmented() rebalances the rbtree, it will callback into * a user provided function to update the augmented information on the * affected subtrees. */ @@ -50,7 +49,7 @@ static inline void rb_insert_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { - __rb_insert_augmented(node, root, false, NULL, augment->rotate); + __rb_insert_augmented(node, root, augment->rotate); } static inline void @@ -58,45 +57,92 @@ rb_insert_augmented_cached(struct rb_node *node, struct rb_root_cached *root, bool newleft, const struct rb_augment_callbacks *augment) { - __rb_insert_augmented(node, &root->rb_root, - newleft, &root->rb_leftmost, augment->rotate); + if (newleft) + root->rb_leftmost = node; + rb_insert_augmented(node, &root->rb_root, augment); } -#define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ - rbtype, rbaugmented, rbcompute) \ +/* + * Template for declaring augmented rbtree callbacks (generic case) + * + * RBSTATIC: 'static' or empty + * RBNAME: name of the rb_augment_callbacks structure + * RBSTRUCT: struct type of the tree nodes + * RBFIELD: name of struct rb_node field within RBSTRUCT + * RBAUGMENTED: name of field within RBSTRUCT holding data for subtree + * RBCOMPUTE: name of function that recomputes the RBAUGMENTED data + */ + +#define RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \ + RBSTRUCT, RBFIELD, RBAUGMENTED, RBCOMPUTE) \ static inline void \ -rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ +RBNAME ## _propagate(struct rb_node *rb, struct rb_node *stop) \ { \ while (rb != stop) { \ - rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ - rbtype augmented = rbcompute(node); \ - if (node->rbaugmented == augmented) \ + RBSTRUCT *node = rb_entry(rb, RBSTRUCT, RBFIELD); \ + if (RBCOMPUTE(node, true)) \ break; \ - node->rbaugmented = augmented; \ - rb = rb_parent(&node->rbfield); \ + rb = rb_parent(&node->RBFIELD); \ } \ } \ static inline void \ -rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ +RBNAME ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ { \ - rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ - rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ - new->rbaugmented = old->rbaugmented; \ + RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \ + RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \ + new->RBAUGMENTED = old->RBAUGMENTED; \ } \ static void \ -rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ +RBNAME ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ { \ - rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ - rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ - new->rbaugmented = old->rbaugmented; \ - old->rbaugmented = rbcompute(old); \ + RBSTRUCT *old = rb_entry(rb_old, RBSTRUCT, RBFIELD); \ + RBSTRUCT *new = rb_entry(rb_new, RBSTRUCT, RBFIELD); \ + new->RBAUGMENTED = old->RBAUGMENTED; \ + RBCOMPUTE(old, false); \ } \ -rbstatic const struct rb_augment_callbacks rbname = { \ - .propagate = rbname ## _propagate, \ - .copy = rbname ## _copy, \ - .rotate = rbname ## _rotate \ +RBSTATIC const struct rb_augment_callbacks RBNAME = { \ + .propagate = RBNAME ## _propagate, \ + .copy = RBNAME ## _copy, \ + .rotate = RBNAME ## _rotate \ }; +/* + * Template for declaring augmented rbtree callbacks, + * computing RBAUGMENTED scalar as max(RBCOMPUTE(node)) for all subtree nodes. + * + * RBSTATIC: 'static' or empty + * RBNAME: name of the rb_augment_callbacks structure + * RBSTRUCT: struct type of the tree nodes + * RBFIELD: name of struct rb_node field within RBSTRUCT + * RBTYPE: type of the RBAUGMENTED field + * RBAUGMENTED: name of RBTYPE field within RBSTRUCT holding data for subtree + * RBCOMPUTE: name of function that returns the per-node RBTYPE scalar + */ + +#define RB_DECLARE_CALLBACKS_MAX(RBSTATIC, RBNAME, RBSTRUCT, RBFIELD, \ + RBTYPE, RBAUGMENTED, RBCOMPUTE) \ +static inline bool RBNAME ## _compute_max(RBSTRUCT *node, bool exit) \ +{ \ + RBSTRUCT *child; \ + RBTYPE max = RBCOMPUTE(node); \ + if (node->RBFIELD.rb_left) { \ + child = rb_entry(node->RBFIELD.rb_left, RBSTRUCT, RBFIELD); \ + if (child->RBAUGMENTED > max) \ + max = child->RBAUGMENTED; \ + } \ + if (node->RBFIELD.rb_right) { \ + child = rb_entry(node->RBFIELD.rb_right, RBSTRUCT, RBFIELD); \ + if (child->RBAUGMENTED > max) \ + max = child->RBAUGMENTED; \ + } \ + if (exit && node->RBAUGMENTED == max) \ + return true; \ + node->RBAUGMENTED = max; \ + return false; \ +} \ +RB_DECLARE_CALLBACKS(RBSTATIC, RBNAME, \ + RBSTRUCT, RBFIELD, RBAUGMENTED, RBNAME ## _compute_max) + #define RB_RED 0 #define RB_BLACK 1 @@ -139,7 +185,6 @@ extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, static __always_inline struct rb_node * __rb_erase_augmented(struct rb_node *node, struct rb_root *root, - struct rb_node **leftmost, const struct rb_augment_callbacks *augment) { struct rb_node *child = node->rb_right; @@ -147,9 +192,6 @@ __rb_erase_augmented(struct rb_node *node, struct rb_root *root, struct rb_node *parent, *rebalance; unsigned long pc; - if (leftmost && node == *leftmost) - *leftmost = rb_next(node); - if (!tmp) { /* * Case 1: node to erase has no more than 1 child (easy!) @@ -249,8 +291,7 @@ static __always_inline void rb_erase_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { - struct rb_node *rebalance = __rb_erase_augmented(node, root, - NULL, augment); + struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); if (rebalance) __rb_erase_color(rebalance, root, augment->rotate); } @@ -259,11 +300,9 @@ static __always_inline void rb_erase_augmented_cached(struct rb_node *node, struct rb_root_cached *root, const struct rb_augment_callbacks *augment) { - struct rb_node *rebalance = __rb_erase_augmented(node, &root->rb_root, - &root->rb_leftmost, - augment); - if (rebalance) - __rb_erase_color(rebalance, &root->rb_root, augment->rotate); + if (root->rb_leftmost == node) + root->rb_leftmost = rb_next(node); + rb_erase_augmented(node, &root->rb_root, augment); } #endif /* _TOOLS_LINUX_RBTREE_AUGMENTED_H */ diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index 1be0e798e362..1fc8faa6e973 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -569,7 +569,7 @@ __SYSCALL(__NR_semget, sys_semget) __SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl) #if defined(__ARCH_WANT_TIME32_SYSCALLS) || __BITS_PER_LONG != 32 #define __NR_semtimedop 192 -__SC_COMP(__NR_semtimedop, sys_semtimedop, sys_semtimedop_time32) +__SC_3264(__NR_semtimedop, sys_semtimedop_time32, sys_semtimedop) #endif #define __NR_semop 193 __SYSCALL(__NR_semop, sys_semop) diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h index 59c71fa8c553..2a616aa3f686 100644 --- a/tools/include/uapi/linux/fs.h +++ b/tools/include/uapi/linux/fs.h @@ -311,6 +311,7 @@ struct fscrypt_key { #define FS_NOCOW_FL 0x00800000 /* Do not cow file */ #define FS_INLINE_DATA_FL 0x10000000 /* Reserved for ext4 */ #define FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ +#define FS_CASEFOLD_FL 0x40000000 /* Folder is case insensitive */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h index 094bb03b9cc2..7da1b37b27aa 100644 --- a/tools/include/uapi/linux/prctl.h +++ b/tools/include/uapi/linux/prctl.h @@ -181,7 +181,7 @@ struct prctl_mm_map { #define PR_GET_THP_DISABLE 42 /* - * Tell the kernel to start/stop helping userspace manage bounds tables. + * No longer implemented, but left here to ensure the numbers stay reserved: */ #define PR_MPX_ENABLE_MANAGEMENT 43 #define PR_MPX_DISABLE_MANAGEMENT 44 @@ -229,4 +229,9 @@ struct prctl_mm_map { # define PR_PAC_APDBKEY (1UL << 3) # define PR_PAC_APGAKEY (1UL << 4) +/* Tagged user address controls for arm64 */ +#define PR_SET_TAGGED_ADDR_CTRL 55 +#define PR_GET_TAGGED_ADDR_CTRL 56 +# define PR_TAGGED_ADDR_ENABLE (1UL << 0) + #endif /* _LINUX_PRCTL_H */ diff --git a/tools/lib/rbtree.c b/tools/lib/rbtree.c index 804f145e3113..2548ff8c4d9c 100644 --- a/tools/lib/rbtree.c +++ b/tools/lib/rbtree.c @@ -83,14 +83,10 @@ __rb_rotate_set_parents(struct rb_node *old, struct rb_node *new, static __always_inline void __rb_insert(struct rb_node *node, struct rb_root *root, - bool newleft, struct rb_node **leftmost, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) { struct rb_node *parent = rb_red_parent(node), *gparent, *tmp; - if (newleft) - *leftmost = node; - while (true) { /* * Loop invariant: node is red. @@ -436,34 +432,17 @@ static const struct rb_augment_callbacks dummy_callbacks = { void rb_insert_color(struct rb_node *node, struct rb_root *root) { - __rb_insert(node, root, false, NULL, dummy_rotate); + __rb_insert(node, root, dummy_rotate); } void rb_erase(struct rb_node *node, struct rb_root *root) { struct rb_node *rebalance; - rebalance = __rb_erase_augmented(node, root, - NULL, &dummy_callbacks); + rebalance = __rb_erase_augmented(node, root, &dummy_callbacks); if (rebalance) ____rb_erase_color(rebalance, root, dummy_rotate); } -void rb_insert_color_cached(struct rb_node *node, - struct rb_root_cached *root, bool leftmost) -{ - __rb_insert(node, &root->rb_root, leftmost, - &root->rb_leftmost, dummy_rotate); -} - -void rb_erase_cached(struct rb_node *node, struct rb_root_cached *root) -{ - struct rb_node *rebalance; - rebalance = __rb_erase_augmented(node, &root->rb_root, - &root->rb_leftmost, &dummy_callbacks); - if (rebalance) - ____rb_erase_color(rebalance, &root->rb_root, dummy_rotate); -} - /* * Augmented rbtree manipulation functions. * @@ -472,10 +451,9 @@ void rb_erase_cached(struct rb_node *node, struct rb_root_cached *root) */ void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, - bool newleft, struct rb_node **leftmost, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) { - __rb_insert(node, root, newleft, leftmost, augment_rotate); + __rb_insert(node, root, augment_rotate); } /* @@ -580,15 +558,6 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new, __rb_change_child(victim, new, parent, root); } -void rb_replace_node_cached(struct rb_node *victim, struct rb_node *new, - struct rb_root_cached *root) -{ - rb_replace_node(victim, new, &root->rb_root); - - if (root->rb_leftmost == victim) - root->rb_leftmost = new; -} - static struct rb_node *rb_left_deepest_node(const struct rb_node *node) { for (;;) { diff --git a/tools/lib/traceevent/Build b/tools/lib/traceevent/Build index ba54bfce0b0b..f9a5d79578f5 100644 --- a/tools/lib/traceevent/Build +++ b/tools/lib/traceevent/Build @@ -6,14 +6,3 @@ libtraceevent-y += parse-utils.o libtraceevent-y += kbuffer-parse.o libtraceevent-y += tep_strerror.o libtraceevent-y += event-parse-api.o - -plugin_jbd2-y += plugin_jbd2.o -plugin_hrtimer-y += plugin_hrtimer.o -plugin_kmem-y += plugin_kmem.o -plugin_kvm-y += plugin_kvm.o -plugin_mac80211-y += plugin_mac80211.o -plugin_sched_switch-y += plugin_sched_switch.o -plugin_function-y += plugin_function.o -plugin_xen-y += plugin_xen.o -plugin_scsi-y += plugin_scsi.o -plugin_cfg80211-y += plugin_cfg80211.o diff --git a/tools/lib/traceevent/Documentation/libtraceevent-event_print.txt b/tools/lib/traceevent/Documentation/libtraceevent-event_print.txt new file mode 100644 index 000000000000..2c6a61811118 --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-event_print.txt @@ -0,0 +1,130 @@ +libtraceevent(3) +================ + +NAME +---- +tep_print_event - Writes event information into a trace sequence. + +SYNOPSIS +-------- +[verse] +-- +*#include <event-parse.h>* +*#include <trace-seq.h>* + +void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seqpass:[*]_s_, struct tep_record pass:[*]_record_, const char pass:[*]_fmt_, _..._) +-- + +DESCRIPTION +----------- + +The _tep_print_event()_ function parses the event information of the given +_record_ and writes it into the trace sequence _s_, according to the format +string _fmt_. The desired information is specified after the format string. +The _fmt_ is printf-like format string, following arguments are supported: +[verse] +-- + TEP_PRINT_PID, "%d" - PID of the event. + TEP_PRINT_CPU, "%d" - Event CPU. + TEP_PRINT_COMM, "%s" - Event command string. + TEP_PRINT_NAME, "%s" - Event name. + TEP_PRINT_LATENCY, "%s" - Latency of the event. It prints 4 or more + fields - interrupt state, scheduling state, + current context, and preemption count. + Field 1 is the interrupt enabled state: + d : Interrupts are disabled + . : Interrupts are enabled + X : The architecture does not support this + information + Field 2 is the "need resched" state. + N : The task is set to call the scheduler when + possible, as another higher priority task + may need to be scheduled in. + . : The task is not set to call the scheduler. + Field 3 is the context state. + . : Normal context + s : Soft interrupt context + h : Hard interrupt context + H : Hard interrupt context which triggered + during soft interrupt context. + z : NMI context + Z : NMI context which triggered during hard + interrupt context + Field 4 is the preemption count. + . : The preempt count is zero. + On preemptible kernels (where the task can be scheduled + out in arbitrary locations while in kernel context), the + preempt count, when non zero, will prevent the kernel + from scheduling out the current task. The preempt count + number is displayed when it is not zero. + Depending on the kernel, it may show other fields + (lock depth, or migration disabled, which are unique to + specialized kernels). + TEP_PRINT_TIME, %d - event time stamp. A divisor and precision can be + specified as part of this format string: + "%precision.divisord". Example: + "%3.1000d" - divide the time by 1000 and print the first + 3 digits before the dot. Thus, the time stamp + "123456000" will be printed as "123.456" + TEP_PRINT_INFO, "%s" - event information. + TEP_PRINT_INFO_RAW, "%s" - event information, in raw format. + +-- +EXAMPLE +------- +[source,c] +-- +#include <event-parse.h> +#include <trace-seq.h> +... +struct trace_seq seq; +trace_seq_init(&seq); +struct tep_handle *tep = tep_alloc(); +... +void print_my_event(struct tep_record *record) +{ + trace_seq_reset(&seq); + tep_print_event(tep, s, record, "%16s-%-5d [%03d] %s %6.1000d %s %s", + TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU, + TEP_PRINT_LATENCY, TEP_PRINT_TIME, TEP_PRINT_NAME, + TEP_PRINT_INFO); +} +... +-- + +FILES +----- +[verse] +-- +*event-parse.h* + Header file to include in order to have access to the library APIs. +*trace-seq.h* + Header file to include in order to have access to trace sequences related APIs. + Trace sequences are used to allow a function to call several other functions + to create a string of data to use. +*-ltraceevent* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +_libtraceevent(3)_, _trace-cmd(1)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. +*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. +-- +REPORTING BUGS +-------------- +Report bugs to <linux-trace-devel@vger.kernel.org> + +LICENSE +------- +libtraceevent is Free Software licensed under the GNU LGPL 2.1 + +RESOURCES +--------- +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git diff --git a/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt b/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt index 38bfea30a5f6..f6aca0df2151 100644 --- a/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt +++ b/tools/lib/traceevent/Documentation/libtraceevent-func_apis.txt @@ -59,12 +59,12 @@ parser context. The _tep_register_function()_ function registers a function name mapped to an address and (optional) module. This mapping is used in case the function tracer -or events have "%pF" or "%pS" parameter in its format string. It is common to -pass in the kallsyms function names with their corresponding addresses with this +or events have "%pS" parameter in its format string. It is common to pass in +the kallsyms function names with their corresponding addresses with this function. The _tep_ argument is the trace event parser context. The _name_ is -the name of the function, the string is copied internally. The _addr_ is -the start address of the function. The _mod_ is the kernel module -the function may be in (NULL for none). +the name of the function, the string is copied internally. The _addr_ is the +start address of the function. The _mod_ is the kernel module the function may +be in (NULL for none). The _tep_register_print_string()_ function registers a string by the address it was stored in the kernel. Some strings internal to the kernel with static diff --git a/tools/lib/traceevent/Documentation/libtraceevent-handle.txt b/tools/lib/traceevent/Documentation/libtraceevent-handle.txt index 8d568316847d..45b20172e262 100644 --- a/tools/lib/traceevent/Documentation/libtraceevent-handle.txt +++ b/tools/lib/traceevent/Documentation/libtraceevent-handle.txt @@ -3,7 +3,7 @@ libtraceevent(3) NAME ---- -tep_alloc, tep_free,tep_ref, tep_unref,tep_ref_get - Create, destroy, manage +tep_alloc, tep_free,tep_ref, tep_unref,tep_get_ref - Create, destroy, manage references of trace event parser context. SYNOPSIS @@ -16,7 +16,7 @@ struct tep_handle pass:[*]*tep_alloc*(void); void *tep_free*(struct tep_handle pass:[*]_tep_); void *tep_ref*(struct tep_handle pass:[*]_tep_); void *tep_unref*(struct tep_handle pass:[*]_tep_); -int *tep_ref_get*(struct tep_handle pass:[*]_tep_); +int *tep_get_ref*(struct tep_handle pass:[*]_tep_); -- DESCRIPTION @@ -57,9 +57,9 @@ EXAMPLE ... struct tep_handle *tep = tep_alloc(); ... -int ref = tep_ref_get(tep); +int ref = tep_get_ref(tep); tep_ref(tep); -if ( (ref+1) != tep_ref_get(tep)) { +if ( (ref+1) != tep_get_ref(tep)) { /* Something wrong happened, the counter is not incremented by 1 */ } tep_unref(tep); diff --git a/tools/lib/traceevent/Documentation/libtraceevent-plugins.txt b/tools/lib/traceevent/Documentation/libtraceevent-plugins.txt new file mode 100644 index 000000000000..596032ade31f --- /dev/null +++ b/tools/lib/traceevent/Documentation/libtraceevent-plugins.txt @@ -0,0 +1,99 @@ +libtraceevent(3) +================ + +NAME +---- +tep_load_plugins, tep_unload_plugins - Load / unload traceevent plugins. + +SYNOPSIS +-------- +[verse] +-- +*#include <event-parse.h>* + +struct tep_plugin_list pass:[*]*tep_load_plugins*(struct tep_handle pass:[*]_tep_); +void *tep_unload_plugins*(struct tep_plugin_list pass:[*]_plugin_list_, struct tep_handle pass:[*]_tep_); +-- + +DESCRIPTION +----------- +The _tep_load_plugins()_ function loads all plugins, located in the plugin +directories. The _tep_ argument is trace event parser context. +The plugin directories are : +[verse] +-- + - System's plugin directory, defined at the library compile time. It + depends on the library installation prefix and usually is + _(install_preffix)/lib/traceevent/plugins_ + - Directory, defined by the environment variable _TRACEEVENT_PLUGIN_DIR_ + - User's plugin directory, located at _~/.local/lib/traceevent/plugins_ +-- +Loading of plugins can be controlled by the _tep_flags_, using the +_tep_set_flag()_ API: +[verse] +-- + _TEP_DISABLE_SYS_PLUGINS_ - do not load plugins, located in + the system's plugin directory. + _TEP_DISABLE_PLUGINS_ - do not load any plugins. +-- +The _tep_set_flag()_ API needs to be called before _tep_load_plugins()_, if +loading of all plugins is not the desired case. + +The _tep_unload_plugins()_ function unloads the plugins, previously loaded by +_tep_load_plugins()_. The _tep_ argument is trace event parser context. The +_plugin_list_ is the list of loaded plugins, returned by +the _tep_load_plugins()_ function. + +RETURN VALUE +------------ +The _tep_load_plugins()_ function returns a list of successfully loaded plugins, +or NULL in case no plugins are loaded. + +EXAMPLE +------- +[source,c] +-- +#include <event-parse.h> +... +struct tep_handle *tep = tep_alloc(); +... +struct tep_plugin_list *plugins = tep_load_plugins(tep); +if (plugins == NULL) { + /* no plugins are loaded */ +} +... +tep_unload_plugins(plugins, tep); +-- + +FILES +----- +[verse] +-- +*event-parse.h* + Header file to include in order to have access to the library APIs. +*-ltraceevent* + Linker switch to add when building a program that uses the library. +-- + +SEE ALSO +-------- +_libtraceevent(3)_, _trace-cmd(1)_, _tep_set_flag(3)_ + +AUTHOR +------ +[verse] +-- +*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*. +*Tzvetomir Stoyanov* <tz.stoyanov@gmail.com>, author of this man page. +-- +REPORTING BUGS +-------------- +Report bugs to <linux-trace-devel@vger.kernel.org> + +LICENSE +------- +libtraceevent is Free Software licensed under the GNU LGPL 2.1 + +RESOURCES +--------- +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git diff --git a/tools/lib/traceevent/Documentation/libtraceevent.txt b/tools/lib/traceevent/Documentation/libtraceevent.txt index fbd977b47de1..d530a7ce8fb2 100644 --- a/tools/lib/traceevent/Documentation/libtraceevent.txt +++ b/tools/lib/traceevent/Documentation/libtraceevent.txt @@ -16,7 +16,7 @@ Management of tep handler data structure and access of its members: void *tep_free*(struct tep_handle pass:[*]_tep_); void *tep_ref*(struct tep_handle pass:[*]_tep_); void *tep_unref*(struct tep_handle pass:[*]_tep_); - int *tep_ref_get*(struct tep_handle pass:[*]_tep_); + int *tep_get_ref*(struct tep_handle pass:[*]_tep_); void *tep_set_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); void *tep_clear_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flag_); bool *tep_test_flag*(struct tep_handle pass:[*]_tep_, enum tep_flag _flags_); @@ -26,15 +26,12 @@ Management of tep handler data structure and access of its members: void *tep_set_long_size*(struct tep_handle pass:[*]_tep_, int _long_size_); int *tep_get_page_size*(struct tep_handle pass:[*]_tep_); void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_); - bool *tep_is_latency_format*(struct tep_handle pass:[*]_tep_); - void *tep_set_latency_format*(struct tep_handle pass:[*]_tep_, int _lat_); int *tep_get_header_page_size*(struct tep_handle pass:[*]_tep_); int *tep_get_header_timestamp_size*(struct tep_handle pass:[*]_tep_); bool *tep_is_old_format*(struct tep_handle pass:[*]_tep_); int *tep_strerror*(struct tep_handle pass:[*]_tep_, enum tep_errno _errnum_, char pass:[*]_buf_, size_t _buflen_); Register / unregister APIs: - int *tep_register_trace_clock*(struct tep_handle pass:[*]_tep_, const char pass:[*]_trace_clock_); int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_); int *tep_register_event_handler*(struct tep_handle pass:[*]_tep_, int _id_, const char pass:[*]_sys_name_, const char pass:[*]_event_name_, tep_event_handler_func _func_, void pass:[*]_context_); int *tep_unregister_event_handler*(struct tep_handle pass:[*]tep, int id, const char pass:[*]sys_name, const char pass:[*]event_name, tep_event_handler_func func, void pass:[*]_context_); @@ -57,14 +54,7 @@ Event related APIs: int *tep_get_events_count*(struct tep_handle pass:[*]_tep_); struct tep_event pass:[*]pass:[*]*tep_list_events*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_); struct tep_event pass:[*]pass:[*]*tep_list_events_copy*(struct tep_handle pass:[*]_tep_, enum tep_event_sort_type _sort_type_); - -Event printing: - void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_, bool _use_trace_clock_); - void *tep_print_event_data*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); - void *tep_event_info*(struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); - void *tep_print_event_task*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]_record_); - void *tep_print_event_time*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_event pass:[*]_event_, struct tep_record pass:[*]record, bool _use_trace_clock_); - void *tep_set_print_raw*(struct tep_handle pass:[*]_tep_, int _print_raw_); + void *tep_print_event*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_, const char pass:[*]_fmt_, _..._); Event finding: struct tep_event pass:[*]*tep_find_event*(struct tep_handle pass:[*]_tep_, int _id_); @@ -116,7 +106,6 @@ Filter management: int *tep_filter_compare*(struct tep_event_filter pass:[*]_filter1_, struct tep_event_filter pass:[*]_filter2_); Parsing various data from the records: - void *tep_data_latency_format*(struct tep_handle pass:[*]_tep_, struct trace_seq pass:[*]_s_, struct tep_record pass:[*]_record_); int *tep_data_type*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); int *tep_data_pid*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); int *tep_data_preempt_count*(struct tep_handle pass:[*]_tep_, struct tep_record pass:[*]_rec_); diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index a39cdd0d890d..5315f3787f8d 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -58,30 +58,6 @@ export man_dir man_dir_SQ INSTALL export DESTDIR DESTDIR_SQ export EVENT_PARSE_VERSION -set_plugin_dir := 1 - -# Set plugin_dir to preffered global plugin location -# If we install under $HOME directory we go under -# $(HOME)/.local/lib/traceevent/plugins -# -# We dont set PLUGIN_DIR in case we install under $HOME -# directory, because by default the code looks under: -# $(HOME)/.local/lib/traceevent/plugins by default. -# -ifeq ($(plugin_dir),) -ifeq ($(prefix),$(HOME)) -override plugin_dir = $(HOME)/.local/lib/traceevent/plugins -set_plugin_dir := 0 -else -override plugin_dir = $(libdir)/traceevent/plugins -endif -endif - -ifeq ($(set_plugin_dir),1) -PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)" -PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' -endif - include ../../scripts/Makefile.include # copy a bit from Linux kbuild @@ -105,7 +81,6 @@ export prefix libdir src obj # Shell quotes libdir_SQ = $(subst ','\'',$(libdir)) libdir_relative_SQ = $(subst ','\'',$(libdir_relative)) -plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) CONFIG_INCLUDES = CONFIG_LIBS = @@ -151,29 +126,14 @@ MAKEOVERRIDES= export srctree OUTPUT CC LD CFLAGS V build := -f $(srctree)/tools/build/Makefile.build dir=. obj -PLUGINS = plugin_jbd2.so -PLUGINS += plugin_hrtimer.so -PLUGINS += plugin_kmem.so -PLUGINS += plugin_kvm.so -PLUGINS += plugin_mac80211.so -PLUGINS += plugin_sched_switch.so -PLUGINS += plugin_function.so -PLUGINS += plugin_xen.so -PLUGINS += plugin_scsi.so -PLUGINS += plugin_cfg80211.so - -PLUGINS := $(addprefix $(OUTPUT),$(PLUGINS)) -PLUGINS_IN := $(PLUGINS:.so=-in.o) - TE_IN := $(OUTPUT)libtraceevent-in.o LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET)) -DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list -CMD_TARGETS = $(LIB_TARGET) $(PLUGINS) $(DYNAMIC_LIST_FILE) +CMD_TARGETS = $(LIB_TARGET) TARGETS = $(CMD_TARGETS) -all: all_cmd +all: all_cmd plugins all_cmd: $(CMD_TARGETS) @@ -188,17 +148,6 @@ $(OUTPUT)libtraceevent.so.$(EVENT_PARSE_VERSION): $(TE_IN) $(OUTPUT)libtraceevent.a: $(TE_IN) $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ -$(OUTPUT)libtraceevent-dynamic-list: $(PLUGINS) - $(QUIET_GEN)$(call do_generate_dynamic_list_file, $(PLUGINS), $@) - -plugins: $(PLUGINS) - -__plugin_obj = $(notdir $@) - plugin_obj = $(__plugin_obj:-in.o=) - -$(PLUGINS_IN): force - $(Q)$(MAKE) $(build)=$(plugin_obj) - $(OUTPUT)%.so: $(OUTPUT)%-in.o $(QUIET_LINK)$(CC) $(CFLAGS) -shared $(LDFLAGS) -nostartfiles -o $@ $^ @@ -258,25 +207,6 @@ define do_install $(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2' endef -define do_install_plugins - for plugin in $1; do \ - $(call do_install,$$plugin,$(plugin_dir_SQ)); \ - done -endef - -define do_generate_dynamic_list_file - symbol_type=`$(NM) -u -D $1 | awk 'NF>1 {print $$1}' | \ - xargs echo "U w W" | tr 'w ' 'W\n' | sort -u | xargs echo`;\ - if [ "$$symbol_type" = "U W" ];then \ - (echo '{'; \ - $(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u;\ - echo '};'; \ - ) > $2; \ - else \ - (echo Either missing one of [$1] or bad version of $(NM)) 1>&2;\ - fi -endef - PKG_CONFIG_FILE = libtraceevent.pc define do_install_pkgconfig_file if [ -n "${pkgconfig_dir}" ]; then \ @@ -296,10 +226,6 @@ install_lib: all_cmd install_plugins install_headers install_pkgconfig $(call do_install_mkdir,$(libdir_SQ)); \ cp -fpR $(LIB_INSTALL) $(DESTDIR)$(libdir_SQ) -install_plugins: $(PLUGINS) - $(call QUIET_INSTALL, trace_plugins) \ - $(call do_install_plugins, $(PLUGINS)) - install_pkgconfig: $(call QUIET_INSTALL, $(PKG_CONFIG_FILE)) \ $(call do_install_pkgconfig_file,$(prefix)) @@ -313,7 +239,7 @@ install_headers: install: install_lib -clean: +clean: clean_plugins $(call QUIET_CLEAN, libtraceevent) \ $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd; \ $(RM) TRACEEVENT-CFLAGS tags TAGS; \ @@ -351,7 +277,19 @@ help: @echo ' doc-install - install the man pages' @echo ' doc-uninstall - uninstall the man pages' @echo'' -PHONY += force plugins + +PHONY += plugins +plugins: + $(call descend,plugins) + +PHONY += install_plugins +install_plugins: + $(call descend,plugins,install) + +PHONY += clean_plugins +clean_plugins: + $(call descend,plugins,clean) + force: # Declare the contents of the .PHONY variable as phony. We keep that diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index bb22238debfe..d948475585ce 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -4367,10 +4367,20 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s switch (*ptr) { case 's': case 'S': - case 'f': - case 'F': case 'x': break; + case 'f': + case 'F': + /* + * Pre-5.5 kernels use %pf and + * %pF for printing symbols + * while kernels since 5.5 use + * %pfw for fwnodes. So check + * %p[fF] isn't followed by 'w'. + */ + if (ptr[1] != 'w') + break; + /* fall through */ default: /* * Older kernels do not process @@ -4487,12 +4497,12 @@ get_bprint_format(void *data, int size __maybe_unused, printk = find_printk(tep, addr); if (!printk) { - if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0) + if (asprintf(&format, "%%ps: (NO FORMAT FOUND at %llx)\n", addr) < 0) return NULL; return format; } - if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0) + if (asprintf(&format, "%s: %s", "%ps", printk->printk) < 0) return NULL; return format; @@ -5517,8 +5527,10 @@ static void print_event_time(struct tep_handle *tep, struct trace_seq *s, if (divstr && isdigit(*(divstr + 1))) div = atoi(divstr + 1); time = record->ts; - if (div) + if (div) { + time += div / 2; time /= div; + } pr = prec; while (pr--) p10 *= 10; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index d438ee44289f..b77837f75a0d 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -441,6 +441,8 @@ int tep_register_print_string(struct tep_handle *tep, const char *fmt, unsigned long long addr); bool tep_is_pid_registered(struct tep_handle *tep, int pid); +struct tep_event *tep_get_event(struct tep_handle *tep, int index); + #define TEP_PRINT_INFO "INFO" #define TEP_PRINT_INFO_RAW "INFO_RAW" #define TEP_PRINT_COMM "COMM" diff --git a/tools/lib/traceevent/plugins/Build b/tools/lib/traceevent/plugins/Build new file mode 100644 index 000000000000..210d26910613 --- /dev/null +++ b/tools/lib/traceevent/plugins/Build @@ -0,0 +1,10 @@ +plugin_jbd2-y += plugin_jbd2.o +plugin_hrtimer-y += plugin_hrtimer.o +plugin_kmem-y += plugin_kmem.o +plugin_kvm-y += plugin_kvm.o +plugin_mac80211-y += plugin_mac80211.o +plugin_sched_switch-y += plugin_sched_switch.o +plugin_function-y += plugin_function.o +plugin_xen-y += plugin_xen.o +plugin_scsi-y += plugin_scsi.o +plugin_cfg80211-y += plugin_cfg80211.o diff --git a/tools/lib/traceevent/plugins/Makefile b/tools/lib/traceevent/plugins/Makefile new file mode 100644 index 000000000000..f440989fa55e --- /dev/null +++ b/tools/lib/traceevent/plugins/Makefile @@ -0,0 +1,222 @@ +# SPDX-License-Identifier: GPL-2.0 + +#MAKEFLAGS += --no-print-directory + + +# Makefiles suck: This macro sets a default value of $(2) for the +# variable named by $(1), unless the variable has been set by +# environment or command line. This is necessary for CC and AR +# because make sets default values, so the simpler ?= approach +# won't work as expected. +define allow-override + $(if $(or $(findstring environment,$(origin $(1))),\ + $(findstring command line,$(origin $(1)))),,\ + $(eval $(1) = $(2))) +endef + +# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. +$(call allow-override,CC,$(CROSS_COMPILE)gcc) +$(call allow-override,AR,$(CROSS_COMPILE)ar) +$(call allow-override,NM,$(CROSS_COMPILE)nm) +$(call allow-override,PKG_CONFIG,pkg-config) + +EXT = -std=gnu99 +INSTALL = install + +# Use DESTDIR for installing into a different root directory. +# This is useful for building a package. The program will be +# installed in this directory as if it was the root directory. +# Then the build tool can move it later. +DESTDIR ?= +DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' + +LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) +ifeq ($(LP64), 1) + libdir_relative = lib64 +else + libdir_relative = lib +endif + +prefix ?= /usr/local +libdir = $(prefix)/$(libdir_relative) + +set_plugin_dir := 1 + +# Set plugin_dir to preffered global plugin location +# If we install under $HOME directory we go under +# $(HOME)/.local/lib/traceevent/plugins +# +# We dont set PLUGIN_DIR in case we install under $HOME +# directory, because by default the code looks under: +# $(HOME)/.local/lib/traceevent/plugins by default. +# +ifeq ($(plugin_dir),) +ifeq ($(prefix),$(HOME)) +override plugin_dir = $(HOME)/.local/lib/traceevent/plugins +set_plugin_dir := 0 +else +override plugin_dir = $(libdir)/traceevent/plugins +endif +endif + +ifeq ($(set_plugin_dir),1) +PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)" +PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' +endif + +include ../../../scripts/Makefile.include + +# copy a bit from Linux kbuild + +ifeq ("$(origin V)", "command line") + VERBOSE = $(V) +endif +ifndef VERBOSE + VERBOSE = 0 +endif + +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(CURDIR))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +#$(info Determined 'srctree' to be $(srctree)) +endif + +export prefix libdir src obj + +# Shell quotes +plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) + +CONFIG_INCLUDES = +CONFIG_LIBS = +CONFIG_FLAGS = + +OBJ = $@ +N = + +INCLUDES = -I. -I.. -I $(srctree)/tools/include $(CONFIG_INCLUDES) + +# Set compile option CFLAGS +ifdef EXTRA_CFLAGS + CFLAGS := $(EXTRA_CFLAGS) +else + CFLAGS := -g -Wall +endif + +# Append required CFLAGS +override CFLAGS += -fPIC +override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) +override CFLAGS += $(udis86-flags) -D_GNU_SOURCE + +ifeq ($(VERBOSE),1) + Q = +else + Q = @ +endif + +# Disable command line variables (CFLAGS) override from top +# level Makefile (perf), otherwise build Makefile will get +# the same command line setup. +MAKEOVERRIDES= + +export srctree OUTPUT CC LD CFLAGS V + +build := -f $(srctree)/tools/build/Makefile.build dir=. obj + +DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list + +PLUGINS = plugin_jbd2.so +PLUGINS += plugin_hrtimer.so +PLUGINS += plugin_kmem.so +PLUGINS += plugin_kvm.so +PLUGINS += plugin_mac80211.so +PLUGINS += plugin_sched_switch.so +PLUGINS += plugin_function.so +PLUGINS += plugin_xen.so +PLUGINS += plugin_scsi.so +PLUGINS += plugin_cfg80211.so + +PLUGINS := $(addprefix $(OUTPUT),$(PLUGINS)) +PLUGINS_IN := $(PLUGINS:.so=-in.o) + +plugins: $(PLUGINS) $(DYNAMIC_LIST_FILE) + +__plugin_obj = $(notdir $@) + plugin_obj = $(__plugin_obj:-in.o=) + +$(PLUGINS_IN): force + $(Q)$(MAKE) $(build)=$(plugin_obj) + +$(OUTPUT)libtraceevent-dynamic-list: $(PLUGINS) + $(QUIET_GEN)$(call do_generate_dynamic_list_file, $(PLUGINS), $@) + +$(OUTPUT)%.so: $(OUTPUT)%-in.o + $(QUIET_LINK)$(CC) $(CFLAGS) -shared $(LDFLAGS) -nostartfiles -o $@ $^ + +define update_dir + (echo $1 > $@.tmp; \ + if [ -r $@ ] && cmp -s $@ $@.tmp; then \ + rm -f $@.tmp; \ + else \ + echo ' UPDATE $@'; \ + mv -f $@.tmp $@; \ + fi); +endef + +tags: force + $(RM) tags + find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ + --regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/' + +TAGS: force + $(RM) TAGS + find . -name '*.[ch]' | xargs etags \ + --regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/' + +define do_install_mkdir + if [ ! -d '$(DESTDIR_SQ)$1' ]; then \ + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \ + fi +endef + +define do_install + $(call do_install_mkdir,$2); \ + $(INSTALL) $(if $3,-m $3,) $1 '$(DESTDIR_SQ)$2' +endef + +define do_install_plugins + for plugin in $1; do \ + $(call do_install,$$plugin,$(plugin_dir_SQ)); \ + done +endef + +define do_generate_dynamic_list_file + symbol_type=`$(NM) -u -D $1 | awk 'NF>1 {print $$1}' | \ + xargs echo "U w W" | tr 'w ' 'W\n' | sort -u | xargs echo`;\ + if [ "$$symbol_type" = "U W" ];then \ + (echo '{'; \ + $(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u;\ + echo '};'; \ + ) > $2; \ + else \ + (echo Either missing one of [$1] or bad version of $(NM)) 1>&2;\ + fi +endef + +install: $(PLUGINS) + $(call QUIET_INSTALL, trace_plugins) \ + $(call do_install_plugins, $(PLUGINS)) + +clean: + $(call QUIET_CLEAN, trace_plugins) \ + $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d .*.cmd; \ + $(RM) $(OUTPUT)libtraceevent-dynamic-list \ + $(RM) TRACEEVENT-CFLAGS tags TAGS; + +PHONY += force plugins +force: + +# Declare the contents of the .PHONY variable as phony. We keep that +# information in a variable so we can use it in if_changed and friends. +.PHONY: $(PHONY) diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugins/plugin_cfg80211.c index 3d43b56a6c98..3d43b56a6c98 100644 --- a/tools/lib/traceevent/plugin_cfg80211.c +++ b/tools/lib/traceevent/plugins/plugin_cfg80211.c diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugins/plugin_function.c index 7770fcb78e0f..7770fcb78e0f 100644 --- a/tools/lib/traceevent/plugin_function.c +++ b/tools/lib/traceevent/plugins/plugin_function.c diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugins/plugin_hrtimer.c index bb434e0ed03a..bb434e0ed03a 100644 --- a/tools/lib/traceevent/plugin_hrtimer.c +++ b/tools/lib/traceevent/plugins/plugin_hrtimer.c diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugins/plugin_jbd2.c index 04fc125f38cb..04fc125f38cb 100644 --- a/tools/lib/traceevent/plugin_jbd2.c +++ b/tools/lib/traceevent/plugins/plugin_jbd2.c diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugins/plugin_kmem.c index edaec5d962c3..edaec5d962c3 100644 --- a/tools/lib/traceevent/plugin_kmem.c +++ b/tools/lib/traceevent/plugins/plugin_kmem.c diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugins/plugin_kvm.c index c8e623065a7e..c8e623065a7e 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugins/plugin_kvm.c diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugins/plugin_mac80211.c index 884303c26b5c..884303c26b5c 100644 --- a/tools/lib/traceevent/plugin_mac80211.c +++ b/tools/lib/traceevent/plugins/plugin_mac80211.c diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugins/plugin_sched_switch.c index 957389a0ff7a..957389a0ff7a 100644 --- a/tools/lib/traceevent/plugin_sched_switch.c +++ b/tools/lib/traceevent/plugins/plugin_sched_switch.c diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugins/plugin_scsi.c index 5d0387a4b65a..5d0387a4b65a 100644 --- a/tools/lib/traceevent/plugin_scsi.c +++ b/tools/lib/traceevent/plugins/plugin_scsi.c diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugins/plugin_xen.c index 993b208d0323..993b208d0323 100644 --- a/tools/lib/traceevent/plugin_xen.c +++ b/tools/lib/traceevent/plugins/plugin_xen.c diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 176f2f084060..044c9a3cb247 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -138,7 +138,6 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, "do_task_dead", "__module_put_and_exit", "complete_and_exit", - "kvm_spurious_fault", "__reiserfs_panic", "lbug_with_loc", "fortify_panic", diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index a269d78456b6..46f7fba2306c 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -924,7 +924,7 @@ ifndef NO_JVMTI JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | awk '{print $$3}') else ifneq (,$(wildcard /usr/sbin/alternatives)) - JDIR=$(shell /usr/sbin/alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g') + JDIR=$(shell /usr/sbin/alternatives --display java | tail -1 | cut -d' ' -f 5 | sed -e 's%/jre/bin/java.%%g' -e 's%/bin/java.%%g') endif endif ifndef JDIR diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index f9807d8c005b..902c792f326a 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -292,7 +292,7 @@ endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a export LIBTRACEEVENT -LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list +LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)plugins/libtraceevent-dynamic-list # # The static build has no dynsym table, so this does not work for @@ -567,7 +567,7 @@ all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) # Create python binding output directory if not already present _dummy := $(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python') -$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) +$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) $(LIBPERF) $(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \ CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ $(PYTHON_WORD) util/setup.py \ @@ -737,7 +737,7 @@ libtraceevent_plugins: FORCE $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins - $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent-dynamic-list + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)plugins/libtraceevent-dynamic-list $(LIBTRACEEVENT)-clean: $(call QUIET_CLEAN, libtraceevent) diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index c32db09baf0d..ede040cf82ad 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -23,9 +23,10 @@ #include "../../util/event.h" #include "../../util/evlist.h" #include "../../util/evsel.h" +#include "../../util/evsel_config.h" #include "../../util/pmu.h" #include "../../util/cs-etm.h" -#include "../../util/util.h" +#include <internal/lib.h> // page_size #include "../../util/session.h" #include <errno.h> @@ -416,7 +417,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, if (err) goto out; - tracking_evsel = perf_evlist__last(evlist); + tracking_evsel = evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); tracking_evsel->core.attr.freq = 0; @@ -648,7 +649,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, if (priv_size != cs_etm_info_priv_size(itr, session->evlist)) return -EINVAL; - if (!session->evlist->nr_mmaps) + if (!session->evlist->core.nr_mmaps) return -EINVAL; /* If the cpu_map is empty all online CPUs are involved */ diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 4b364692da67..eba6541ec0f1 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -16,7 +16,7 @@ #include "../../util/evsel.h" #include "../../util/evlist.h" #include "../../util/session.h" -#include "../../util/util.h" +#include <internal/lib.h> // page_size #include "../../util/pmu.h" #include "../../util/debug.h" #include "../../util/auxtrace.h" @@ -51,7 +51,7 @@ static int arm_spe_info_fill(struct auxtrace_record *itr, if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE) return -EINVAL; - if (!session->evlist->nr_mmaps) + if (!session->evlist->core.nr_mmaps) return -EINVAL; auxtrace_info->type = PERF_AUXTRACE_ARM_SPE; @@ -129,7 +129,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, if (err) return err; - tracking_evsel = perf_evlist__last(evlist); + tracking_evsel = evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); tracking_evsel->core.attr.freq = 0; diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c index b047b882c5b1..917b97d7c5d3 100644 --- a/tools/perf/arch/arm64/util/dwarf-regs.c +++ b/tools/perf/arch/arm64/util/dwarf-regs.c @@ -11,7 +11,6 @@ #include <dwarf-regs.h> #include <linux/ptrace.h> /* for struct user_pt_regs */ #include <linux/stringify.h> -#include "util.h" struct pt_regs_dwarfnum { const char *name; diff --git a/tools/perf/arch/arm64/util/header.c b/tools/perf/arch/arm64/util/header.c index e41defaaa2e6..a32e4b72a98f 100644 --- a/tools/perf/arch/arm64/util/header.c +++ b/tools/perf/arch/arm64/util/header.c @@ -1,5 +1,7 @@ #include <stdio.h> #include <stdlib.h> +#include <perf/cpumap.h> +#include <internal/cpumap.h> #include <api/fs/fs.h> #include "debug.h" #include "header.h" @@ -29,7 +31,7 @@ char *get_cpuid_str(struct perf_pmu *pmu) /* read midr from list of cpus mapped to this pmu */ cpus = perf_cpu_map__get(pmu->cpus); - for (cpu = 0; cpu < cpus->nr; cpu++) { + for (cpu = 0; cpu < perf_cpu_map__nr(cpus); cpu++) { scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d"MIDR, sysfs, cpus->map[cpu]); diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index 002520d4036b..1495a9523a23 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -5,8 +5,8 @@ #include <libunwind.h> #include "perf_regs.h" #include "../../util/unwind.h" -#include "../../util/debug.h" #endif +#include "../../util/debug.h" int LIBUNWIND__ARCH_REG_ID(int regnum) { diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c index 4952890b9428..0c4f4caf53ac 100644 --- a/tools/perf/arch/powerpc/util/dwarf-regs.c +++ b/tools/perf/arch/powerpc/util/dwarf-regs.c @@ -12,7 +12,6 @@ #include <linux/ptrace.h> #include <linux/kernel.h> #include <linux/stringify.h> -#include "util.h" struct pt_regs_dwarfnum { const char *name; diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index 0b242664f5ea..b6b7bc7e31a1 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c @@ -6,7 +6,6 @@ #include <string.h> #include <linux/stringify.h> #include "header.h" -#include "util.h" #define mfspr(rn) ({unsigned long rval; \ asm volatile("mfspr %0," __stringify(rn) \ diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c index f0dbf7b075c8..9cc1c4a9dec4 100644 --- a/tools/perf/arch/powerpc/util/kvm-stat.c +++ b/tools/perf/arch/powerpc/util/kvm-stat.c @@ -5,9 +5,11 @@ #include "util/debug.h" #include "util/evsel.h" #include "util/evlist.h" +#include "util/pmu.h" #include "book3s_hv_exits.h" #include "book3s_hcalls.h" +#include <subcmd/parse-options.h> #define NR_TPS 4 @@ -172,3 +174,46 @@ int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused) return ret; } + +/* + * Incase of powerpc architecture, pmu registers are programmable + * by guest kernel. So monitoring guest via host may not provide + * valid samples with default 'cycles' event. It is better to use + * 'trace_imc/trace_cycles' event for guest profiling, since it + * can track the guest instruction pointer in the trace-record. + * + * Function to parse the arguments and return appropriate values. + */ +int kvm_add_default_arch_event(int *argc, const char **argv) +{ + const char **tmp; + bool event = false; + int i, j = *argc; + + const struct option event_options[] = { + OPT_BOOLEAN('e', "event", &event, NULL), + OPT_END() + }; + + tmp = calloc(j + 1, sizeof(char *)); + if (!tmp) + return -EINVAL; + + for (i = 0; i < j; i++) + tmp[i] = argv[i]; + + parse_options(j, tmp, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN); + if (!event) { + if (pmu_have_event("trace_imc", "trace_cycles")) { + argv[j++] = strdup("-e"); + argv[j++] = strdup("trace_imc/trace_cycles/"); + *argc += 2; + } else { + free(tmp); + return -EINVAL; + } + } + + free(tmp); + return 0; +} diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index fc9c2f5fcd52..3018a054526a 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -13,6 +13,7 @@ #include "util/callchain.h" #include "util/debug.h" #include "util/dso.h" +#include "util/event.h" // struct ip_callchain #include "util/map.h" #include "util/symbol.h" diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 8a4b717e0a53..abb7a12d8f93 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -4,7 +4,6 @@ * Copyright (C) 2015 Naveen N. Rao, IBM Corporation */ -#include "debug.h" #include "dso.h" #include "symbol.h" #include "map.h" diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile index cb198787570a..6ac8887be7c9 100644 --- a/tools/perf/arch/s390/Makefile +++ b/tools/perf/arch/s390/Makefile @@ -4,6 +4,7 @@ PERF_HAVE_DWARF_REGS := 1 endif HAVE_KVM_STAT_SUPPORT := 1 PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 +PERF_HAVE_JITDUMP := 1 # # Syscall table generation for perf diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c index b0fb70e38960..0db5c58c98e8 100644 --- a/tools/perf/arch/s390/util/auxtrace.c +++ b/tools/perf/arch/s390/util/auxtrace.c @@ -1,4 +1,5 @@ #include <stdbool.h> +#include <stdlib.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/bitops.h> diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c index c8c86a0c9b79..724efb2d842d 100644 --- a/tools/perf/arch/s390/util/machine.c +++ b/tools/perf/arch/s390/util/machine.c @@ -2,7 +2,7 @@ #include <unistd.h> #include <stdio.h> #include <string.h> -#include "util.h" +#include <internal/lib.h> // page_size #include "machine.h" #include "api/fs/fs.h" #include "debug.h" diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c index 3b5cc3373821..3ec562a2aaba 100644 --- a/tools/perf/arch/x86/tests/intel-cqm.c +++ b/tools/perf/arch/x86/tests/intel-cqm.c @@ -5,7 +5,7 @@ #include "evlist.h" #include "evsel.h" #include "arch-tests.h" -#include "util.h" +#include <internal/lib.h> // page_size #include <signal.h> #include <sys/mman.h> @@ -63,9 +63,9 @@ int test__intel_cqm_count_nmi_context(struct test *test __maybe_unused, int subt goto out; } - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); if (!evsel) { - pr_debug("perf_evlist__first failed\n"); + pr_debug("evlist__first failed\n"); goto out; } diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index eb3635941c2b..fa947952c16a 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c @@ -15,9 +15,9 @@ #include "evlist.h" #include "evsel.h" #include "thread_map.h" -#include "cpumap.h" #include "record.h" #include "tsc.h" +#include "util/mmap.h" #include "tests/tests.h" #include "arch-tests.h" @@ -66,7 +66,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe union perf_event *event; u64 test_tsc, comm1_tsc, comm2_tsc; u64 test_time, comm1_time = 0, comm2_time = 0; - struct perf_mmap *md; + struct mmap *md; threads = thread_map__new(-1, getpid(), UINT_MAX); CHECK_NOT_NULL__(threads); @@ -83,7 +83,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe perf_evlist__config(evlist, &opts, NULL); - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); evsel->core.attr.comm = 1; evsel->core.attr.disabled = 1; @@ -91,9 +91,9 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe CHECK__(evlist__open(evlist)); - CHECK__(perf_evlist__mmap(evlist, UINT_MAX)); + CHECK__(evlist__mmap(evlist, UINT_MAX)); - pc = evlist->mmap[0].base; + pc = evlist->mmap[0].core.base; ret = perf_read_tsc_conversion(pc, &tc); if (ret) { if (ret == -EOPNOTSUPP) { @@ -115,7 +115,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe evlist__disable(evlist); - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) continue; diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c index 6e67cee792b1..1ea916656a2d 100644 --- a/tools/perf/arch/x86/tests/rdpmc.c +++ b/tools/perf/arch/x86/tests/rdpmc.c @@ -13,7 +13,7 @@ #include "tests/tests.h" #include "cloexec.h" #include "event.h" -#include "util.h" +#include <internal/lib.h> // page_size #include "arch-tests.h" static u64 rdpmc(unsigned int counter) diff --git a/tools/perf/arch/x86/util/archinsn.c b/tools/perf/arch/x86/util/archinsn.c index 9876c7a7ed7c..3e6791531ca5 100644 --- a/tools/perf/arch/x86/util/archinsn.c +++ b/tools/perf/arch/x86/util/archinsn.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "../../../../arch/x86/include/asm/insn.h" #include "archinsn.h" +#include "event.h" #include "machine.h" #include "thread.h" #include "symbol.h" diff --git a/tools/perf/arch/x86/util/event.c b/tools/perf/arch/x86/util/event.c index a3a0b6884779..d357c625c09f 100644 --- a/tools/perf/arch/x86/util/event.c +++ b/tools/perf/arch/x86/util/event.c @@ -3,6 +3,8 @@ #include <linux/string.h> #include <linux/zalloc.h> +#include "../../util/event.h" +#include "../../util/synthetic-events.h" #include "../../util/machine.h" #include "../../util/tool.h" #include "../../util/map.h" diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index d263430c045f..f7f68a50a5cd 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c @@ -15,6 +15,7 @@ #include "../../util/event.h" #include "../../util/evsel.h" #include "../../util/evlist.h" +#include "../../util/mmap.h" #include "../../util/session.h" #include "../../util/pmu.h" #include "../../util/debug.h" @@ -22,7 +23,7 @@ #include "../../util/tsc.h" #include "../../util/auxtrace.h" #include "../../util/intel-bts.h" -#include "../../util/util.h" +#include <internal/lib.h> // page_size #define KiB(x) ((x) * 1024) #define MiB(x) ((x) * 1024 * 1024) @@ -74,10 +75,10 @@ static int intel_bts_info_fill(struct auxtrace_record *itr, if (priv_size != INTEL_BTS_AUXTRACE_PRIV_SIZE) return -EINVAL; - if (!session->evlist->nr_mmaps) + if (!session->evlist->core.nr_mmaps) return -EINVAL; - pc = session->evlist->mmap[0].base; + pc = session->evlist->mmap[0].core.base; if (pc) { err = perf_read_tsc_conversion(pc, &tc); if (err) { @@ -230,7 +231,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, if (err) return err; - tracking_evsel = perf_evlist__last(evlist); + tracking_evsel = evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index cb7cf16af79c..d6d26256915f 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -18,6 +18,7 @@ #include "../../util/evlist.h" #include "../../util/evsel.h" #include "../../util/cpumap.h" +#include "../../util/mmap.h" #include <subcmd/parse-options.h> #include "../../util/parse-events.h" #include "../../util/pmu.h" @@ -26,7 +27,7 @@ #include "../../util/record.h" #include "../../util/target.h" #include "../../util/tsc.h" -#include "../../util/util.h" +#include <internal/lib.h> // page_size #include "../../util/intel-pt.h" #define KiB(x) ((x) * 1024) @@ -351,10 +352,10 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, filter = intel_pt_find_filter(session->evlist, ptr->intel_pt_pmu); filter_str_len = filter ? strlen(filter) : 0; - if (!session->evlist->nr_mmaps) + if (!session->evlist->core.nr_mmaps) return -EINVAL; - pc = session->evlist->mmap[0].base; + pc = session->evlist->mmap[0].core.base; if (pc) { err = perf_read_tsc_conversion(pc, &tc); if (err) { @@ -416,12 +417,12 @@ static int intel_pt_track_switches(struct evlist *evlist) return err; } - evsel = perf_evlist__last(evlist); + evsel = evlist__last(evlist); perf_evsel__set_sample_bit(evsel, CPU); perf_evsel__set_sample_bit(evsel, TIME); - evsel->system_wide = true; + evsel->core.system_wide = true; evsel->no_aux_samples = true; evsel->immediate = true; @@ -716,13 +717,13 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, if (err) return err; - switch_evsel = perf_evlist__last(evlist); + switch_evsel = evlist__last(evlist); switch_evsel->core.attr.freq = 0; switch_evsel->core.attr.sample_period = 1; switch_evsel->core.attr.context_switch = 1; - switch_evsel->system_wide = true; + switch_evsel->core.system_wide = true; switch_evsel->no_aux_samples = true; switch_evsel->immediate = true; @@ -774,7 +775,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, if (err) return err; - tracking_evsel = perf_evlist__last(evlist); + tracking_evsel = evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); diff --git a/tools/perf/arch/x86/util/machine.c b/tools/perf/arch/x86/util/machine.c index 1e9ec783b9a1..e17e080e76f4 100644 --- a/tools/perf/arch/x86/util/machine.c +++ b/tools/perf/arch/x86/util/machine.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/types.h> #include <linux/string.h> +#include <limits.h> #include <stdlib.h> -#include "../../util/util.h" +#include <internal/lib.h> // page_size #include "../../util/machine.h" #include "../../util/map.h" #include "../../util/symbol.h" diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index c5197a15119b..2f55afb14e1f 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c @@ -8,6 +8,8 @@ #include <linux/types.h> #include <asm/barrier.h> #include "../../../util/debug.h" +#include "../../../util/event.h" +#include "../../../util/synthetic-events.h" #include "../../../util/tsc.h" int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index 05920e3edf7a..47357973b55b 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> +#include "../../util/debug.h" #ifndef REMOTE_UNWIND_LIBUNWIND #include <libunwind.h> #include "perf_regs.h" #include "../../util/unwind.h" -#include "../../util/debug.h" #endif #ifdef HAVE_ARCH_X86_64_SUPPORT diff --git a/tools/perf/bench/epoll-ctl.c b/tools/perf/bench/epoll-ctl.c index d1caa4a0a12a..bb617e568841 100644 --- a/tools/perf/bench/epoll-ctl.c +++ b/tools/perf/bench/epoll-ctl.c @@ -21,12 +21,12 @@ #include <sys/resource.h> #include <sys/epoll.h> #include <sys/eventfd.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "../util/stat.h" #include <subcmd/parse-options.h> #include "bench.h" -#include "cpumap.h" #include <err.h> diff --git a/tools/perf/bench/epoll-wait.c b/tools/perf/bench/epoll-wait.c index f6b4472847d2..7af694437f4e 100644 --- a/tools/perf/bench/epoll-wait.c +++ b/tools/perf/bench/epoll-wait.c @@ -76,12 +76,12 @@ #include <sys/epoll.h> #include <sys/eventfd.h> #include <sys/types.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "../util/stat.h" #include <subcmd/parse-options.h> #include "bench.h" -#include "cpumap.h" #include <err.h> diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index 80e138904c66..8ba0c3330a9a 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c @@ -20,13 +20,13 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <sys/time.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "../util/stat.h" #include <subcmd/parse-options.h> #include "bench.h" #include "futex.h" -#include "cpumap.h" #include <err.h> diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index c5d6d0abbaa9..d0cae8125423 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c @@ -14,10 +14,10 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <errno.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "bench.h" #include "futex.h" -#include "cpumap.h" #include <err.h> #include <stdlib.h> diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index 75d3418c1a88..a00a6891447a 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c @@ -20,10 +20,10 @@ #include <linux/kernel.h> #include <linux/time64.h> #include <errno.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "bench.h" #include "futex.h" -#include "cpumap.h" #include <err.h> #include <stdlib.h> diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c index 163fe16c275a..a053cf2b7039 100644 --- a/tools/perf/bench/futex-wake-parallel.c +++ b/tools/perf/bench/futex-wake-parallel.c @@ -29,7 +29,8 @@ int bench_futex_wake_parallel(int argc __maybe_unused, const char **argv __maybe #include <linux/time64.h> #include <errno.h> #include "futex.h" -#include "cpumap.h" +#include <internal/cpumap.h> +#include <perf/cpumap.h> #include <err.h> #include <stdlib.h> diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index 77dcdc13618a..df810096abfe 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c @@ -20,10 +20,10 @@ #include <linux/kernel.h> #include <linux/time64.h> #include <errno.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "bench.h" #include "futex.h" -#include "cpumap.h" #include <err.h> #include <stdlib.h> diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 62b8ef4bcb1f..5797253b9700 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -9,7 +9,6 @@ /* For the CLR_() macros */ #include <pthread.h> -#include "../builtin.h" #include <subcmd/parse-options.h> #include "../util/cloexec.h" diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index c63eb9a46346..97e4a4fb3362 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c @@ -10,9 +10,7 @@ * */ -#include "../util/util.h" #include <subcmd/parse-options.h> -#include "../builtin.h" #include "bench.h" /* Test groups of 20 processes spraying to 20 receivers */ diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 35b07f197d48..3c88d1f201f1 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c @@ -9,9 +9,7 @@ * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> */ -#include "../util/util.h" #include <subcmd/parse-options.h> -#include "../builtin.h" #include "bench.h" #include <unistd.h> diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4e4d2e76232e..8db8fc9bddef 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -27,6 +27,7 @@ #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" @@ -39,6 +40,7 @@ #include <dlfcn.h> #include <errno.h> #include <linux/bitmap.h> +#include <linux/err.h> struct perf_annotate { struct perf_tool tool; @@ -583,8 +585,8 @@ int cmd_annotate(int argc, const char **argv) data.path = input_name; annotate.session = perf_session__new(&data, false, &annotate.tool); - if (annotate.session == NULL) - return -1; + if (IS_ERR(annotate.session)) + return PTR_ERR(annotate.session); annotate.has_br_stack = perf_header__has_feat(&annotate.session->header, HEADER_BRANCH_STACK); diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 1a69eb565dc0..39efa51d7fb3 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c @@ -28,6 +28,7 @@ #include "util/util.h" #include "util/probe-file.h" #include <linux/string.h> +#include <linux/err.h> static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid) { @@ -422,8 +423,8 @@ int cmd_buildid_cache(int argc, const char **argv) data.force = force; session = perf_session__new(&data, false, NULL); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); } if (symbol__init(session ? &session->header.env : NULL) < 0) diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 5a0d8b378cb5..e3ef75583514 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -18,6 +18,7 @@ #include "util/symbol.h" #include "util/data.h" #include <errno.h> +#include <linux/err.h> static int sysfs__fprintf_build_id(FILE *fp) { @@ -65,8 +66,8 @@ static int perf_session__list_build_ids(bool force, bool with_hits) goto out; session = perf_session__new(&data, false, &build_id__mark_dso_hit_ops); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); /* * We take all buildids when the file contains AUX area tracing data diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index b09b12e0976b..3542b6ab9813 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -13,6 +13,7 @@ #include <errno.h> #include <inttypes.h> #include <linux/compiler.h> +#include <linux/err.h> #include <linux/kernel.h> #include <linux/stringify.h> #include <linux/zalloc.h> @@ -20,6 +21,7 @@ #include <sys/param.h> #include "debug.h" #include "builtin.h" +#include <perf/cpumap.h> #include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "map_symbol.h" @@ -2780,8 +2782,9 @@ static int perf_c2c__report(int argc, const char **argv) } session = perf_session__new(&data, 0, &c2c.tool); - if (session == NULL) { - pr_debug("No memory for session\n"); + if (IS_ERR(session)) { + err = PTR_ERR(session); + pr_debug("Error creating perf session\n"); goto out; } diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 42d8157e047a..2603015f98be 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -9,7 +9,6 @@ #include "util/cache.h" #include <subcmd/parse-options.h> -#include "util/util.h" #include "util/debug.h" #include "util/config.h" #include <linux/string.h> diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 827e4800d862..c37a78677955 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -23,6 +23,7 @@ #include "util/time-utils.h" #include "util/annotate.h" #include "util/map.h" +#include <linux/err.h> #include <linux/zalloc.h> #include <subcmd/pager.h> #include <subcmd/parse-options.h> @@ -1153,9 +1154,9 @@ static int check_file_brstack(void) data__for_each_file(i, d) { d->session = perf_session__new(&d->data, false, &pdiff.tool); - if (!d->session) { + if (IS_ERR(d->session)) { pr_err("Failed to open %s\n", d->data.path); - return -1; + return PTR_ERR(d->session); } has_br_stack = perf_header__has_feat(&d->session->header, @@ -1185,9 +1186,9 @@ static int __cmd_diff(void) data__for_each_file(i, d) { d->session = perf_session__new(&d->data, false, &pdiff.tool); - if (!d->session) { + if (IS_ERR(d->session)) { + ret = PTR_ERR(d->session); pr_err("Failed to open %s\n", d->data.path); - ret = -1; goto out_delete; } diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 238fa3876805..440501994931 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -5,18 +5,18 @@ */ #include "builtin.h" -#include "util/util.h" - #include <linux/list.h> #include "perf.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evsel_fprintf.h" #include "util/parse-events.h" #include <subcmd/parse-options.h> #include "util/session.h" #include "util/data.h" #include "util/debug.h" +#include <linux/err.h> static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) { @@ -30,8 +30,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details bool has_tracepoint = false; session = perf_session__new(&data, 0, NULL); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); evlist__for_each_entry(session->evlist, pos) { perf_evsel__fprintf(pos, details, stdout); diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index c14f40b858bc..372ecb3e2c06 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -21,7 +21,9 @@ #include "util/auxtrace.h" #include "util/jit.h" #include "util/symbol.h" +#include "util/synthetic-events.h" #include "util/thread.h" +#include <linux/err.h> #include <subcmd/parse-options.h> @@ -834,8 +836,8 @@ int cmd_inject(int argc, const char **argv) data.path = inject.input_name; inject.session = perf_session__new(&data, true, &inject.tool); - if (inject.session == NULL) - return -1; + if (IS_ERR(inject.session)) + return PTR_ERR(inject.session); if (zstd_init(&(inject.session->zstd_data), 0) < 0) pr_warning("Decompression initialization failed.\n"); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index b5682beaad72..1e61e353f579 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -14,6 +14,7 @@ #include "util/tool.h" #include "util/callchain.h" #include "util/time-utils.h" +#include <linux/err.h> #include <subcmd/pager.h> #include <subcmd/parse-options.h> @@ -1956,8 +1957,8 @@ int cmd_kmem(int argc, const char **argv) data.path = input_name; kmem_session = session = perf_session__new(&data, false, &perf_kmem); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); ret = -1; diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 0a4fcbe32bf6..2227e2f42c09 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -5,6 +5,7 @@ #include "util/build-id.h" #include "util/evsel.h" #include "util/evlist.h" +#include "util/mmap.h" #include "util/term.h" #include "util/symbol.h" #include "util/thread.h" @@ -17,9 +18,11 @@ #include "util/debug.h" #include "util/tool.h" #include "util/stat.h" +#include "util/synthetic-events.h" #include "util/top.h" #include "util/data.h" #include "util/ordered-events.h" +#include "util/kvm-stat.h" #include "ui/ui.h" #include <sys/prctl.h> @@ -31,6 +34,7 @@ #include <sys/stat.h> #include <fcntl.h> +#include <linux/err.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/time64.h> @@ -58,7 +62,6 @@ static const char *get_filename_for_perf_kvm(void) } #ifdef HAVE_KVM_STAT_SUPPORT -#include "util/kvm-stat.h" void exit_event_get_key(struct evsel *evsel, struct perf_sample *sample, @@ -748,7 +751,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, { struct evlist *evlist = kvm->evlist; union perf_event *event; - struct perf_mmap *md; + struct mmap *md; u64 timestamp; s64 n = 0; int err; @@ -799,7 +802,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm) s64 n, ntotal = 0; u64 flush_time = ULLONG_MAX, mmap_time; - for (i = 0; i < kvm->evlist->nr_mmaps; i++) { + for (i = 0; i < kvm->evlist->core.nr_mmaps; i++) { n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time); if (n < 0) return -1; @@ -964,10 +967,10 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) goto out; } - if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0) + if (evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0) goto out; - nr_stdin = perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)); + nr_stdin = evlist__add_pollfd(kvm->evlist, fileno(stdin)); if (nr_stdin < 0) goto out; @@ -978,7 +981,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) evlist__enable(kvm->evlist); while (!done) { - struct fdarray *fda = &kvm->evlist->pollfd; + struct fdarray *fda = &kvm->evlist->core.pollfd; int rc; rc = perf_kvm__mmap_read(kvm); @@ -1058,7 +1061,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) goto out; } - if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) { + if (evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) { ui__error("Failed to mmap the events: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); evlist__close(evlist); @@ -1090,9 +1093,9 @@ static int read_events(struct perf_kvm_stat *kvm) kvm->tool = eops; kvm->session = perf_session__new(&file, false, &kvm->tool); - if (!kvm->session) { + if (IS_ERR(kvm->session)) { pr_err("Initializing perf session failed\n"); - return -1; + return PTR_ERR(kvm->session); } symbol__init(&kvm->session->header.env); @@ -1445,8 +1448,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, * perf session */ kvm->session = perf_session__new(&data, false, &kvm->tool); - if (kvm->session == NULL) { - err = -1; + if (IS_ERR(kvm->session)) { + err = PTR_ERR(kvm->session); goto out; } kvm->session->evlist = kvm->evlist; @@ -1513,11 +1516,21 @@ perf_stat: } #endif /* HAVE_KVM_STAT_SUPPORT */ +int __weak kvm_add_default_arch_event(int *argc __maybe_unused, + const char **argv __maybe_unused) +{ + return 0; +} + static int __cmd_record(const char *file_name, int argc, const char **argv) { - int rec_argc, i = 0, j; + int rec_argc, i = 0, j, ret; const char **rec_argv; + ret = kvm_add_default_arch_event(&argc, argv); + if (ret) + return -EINVAL; + rec_argc = argc + 2; rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("record"); diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index e290f6b348d8..08e62ae9d37e 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -81,9 +81,9 @@ int cmd_list(int argc, const char **argv) long_desc_flag, details_flag); else if (strcmp(argv[i], "sdt") == 0) print_sdt_events(NULL, NULL, raw_dump); - else if (strcmp(argv[i], "metric") == 0) + else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0) metricgroup__print(true, false, NULL, raw_dump, details_flag); - else if (strcmp(argv[i], "metricgroup") == 0) + else if (strcmp(argv[i], "metricgroup") == 0 || strcmp(argv[i], "metricgroups") == 0) metricgroup__print(false, true, NULL, raw_dump, details_flag); else if ((sep = strchr(argv[i], ':')) != NULL) { int sep_idx; diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 4c2b7f437cdf..474dfd59d7eb 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -30,6 +30,7 @@ #include <linux/hash.h> #include <linux/kernel.h> #include <linux/zalloc.h> +#include <linux/err.h> static struct perf_session *session; @@ -872,9 +873,9 @@ static int __cmd_report(bool display_info) }; session = perf_session__new(&data, false, &eops); - if (!session) { + if (IS_ERR(session)) { pr_err("Initializing perf session failed\n"); - return -1; + return PTR_ERR(session); } symbol__init(&session->header.env); diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 27d2bde943a8..a13f5817d6fc 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c @@ -17,6 +17,7 @@ #include "util/dso.h" #include "util/map.h" #include "util/symbol.h" +#include <linux/err.h> #define MEM_OPERATION_LOAD 0x1 #define MEM_OPERATION_STORE 0x2 @@ -249,8 +250,8 @@ static int report_raw_events(struct perf_mem *mem) struct perf_session *session = perf_session__new(&data, false, &mem->tool); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); if (mem->cpu_list) { ret = perf_session__cpu_bitmap(session, mem->cpu_list, diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1447004eee8a..23332861de6e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -20,6 +20,7 @@ #include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" +#include "util/mmap.h" #include "util/target.h" #include "util/session.h" #include "util/tool.h" @@ -38,6 +39,7 @@ #include "util/trigger.h" #include "util/perf-hooks.h" #include "util/cpu-set-sched.h" +#include "util/synthetic-events.h" #include "util/time-utils.h" #include "util/units.h" #include "util/bpf-event.h" @@ -53,6 +55,7 @@ #include <signal.h> #include <sys/mman.h> #include <sys/wait.h> +#include <linux/err.h> #include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> @@ -117,7 +120,7 @@ static bool switch_output_time(struct record *rec) trigger_is_ready(&switch_output_trigger); } -static int record__write(struct record *rec, struct perf_mmap *map __maybe_unused, +static int record__write(struct record *rec, struct mmap *map __maybe_unused, void *bf, size_t size) { struct perf_data_file *file = &rec->session->data->file; @@ -166,7 +169,7 @@ static int record__aio_write(struct aiocb *cblock, int trace_fd, return rc; } -static int record__aio_complete(struct perf_mmap *md, struct aiocb *cblock) +static int record__aio_complete(struct mmap *md, struct aiocb *cblock) { void *rem_buf; off_t rem_off; @@ -212,7 +215,7 @@ static int record__aio_complete(struct perf_mmap *md, struct aiocb *cblock) return rc; } -static int record__aio_sync(struct perf_mmap *md, bool sync_all) +static int record__aio_sync(struct mmap *md, bool sync_all) { struct aiocb **aiocb = md->aio.aiocb; struct aiocb *cblocks = md->aio.cblocks; @@ -253,12 +256,12 @@ struct record_aio { size_t size; }; -static int record__aio_pushfn(struct perf_mmap *map, void *to, void *buf, size_t size) +static int record__aio_pushfn(struct mmap *map, void *to, void *buf, size_t size) { struct record_aio *aio = to; /* - * map->base data pointed by buf is copied into free map->aio.data[] buffer + * map->core.base data pointed by buf is copied into free map->aio.data[] buffer * to release space in the kernel buffer as fast as possible, calling * perf_mmap__consume() from perf_mmap__push() function. * @@ -298,7 +301,7 @@ static int record__aio_pushfn(struct perf_mmap *map, void *to, void *buf, size_t return size; } -static int record__aio_push(struct record *rec, struct perf_mmap *map, off_t *off) +static int record__aio_push(struct record *rec, struct mmap *map, off_t *off) { int ret, idx; int trace_fd = rec->session->data->file.fd; @@ -349,15 +352,15 @@ static void record__aio_mmap_read_sync(struct record *rec) { int i; struct evlist *evlist = rec->evlist; - struct perf_mmap *maps = evlist->mmap; + struct mmap *maps = evlist->mmap; if (!record__aio_enabled(rec)) return; - for (i = 0; i < evlist->nr_mmaps; i++) { - struct perf_mmap *map = &maps[i]; + for (i = 0; i < evlist->core.nr_mmaps; i++) { + struct mmap *map = &maps[i]; - if (map->base) + if (map->core.base) record__aio_sync(map, true); } } @@ -385,7 +388,7 @@ static int record__aio_parse(const struct option *opt, #else /* HAVE_AIO_SUPPORT */ static int nr_cblocks_max = 0; -static int record__aio_push(struct record *rec __maybe_unused, struct perf_mmap *map __maybe_unused, +static int record__aio_push(struct record *rec __maybe_unused, struct mmap *map __maybe_unused, off_t *off __maybe_unused) { return -1; @@ -437,7 +440,7 @@ static int record__mmap_flush_parse(const struct option *opt, if (!opts->mmap_flush) opts->mmap_flush = MMAP_FLUSH_DEFAULT; - flush_max = perf_evlist__mmap_size(opts->mmap_pages); + flush_max = evlist__mmap_size(opts->mmap_pages); flush_max /= 4; if (opts->mmap_flush > flush_max) opts->mmap_flush = flush_max; @@ -480,7 +483,7 @@ static int process_synthesized_event(struct perf_tool *tool, return record__write(rec, NULL, event, event->header.size); } -static int record__pushfn(struct perf_mmap *map, void *to, void *bf, size_t size) +static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size) { struct record *rec = to; @@ -525,7 +528,7 @@ static void record__sig_exit(void) #ifdef HAVE_AUXTRACE_SUPPORT static int record__process_auxtrace(struct perf_tool *tool, - struct perf_mmap *map, + struct mmap *map, union perf_event *event, void *data1, size_t len1, void *data2, size_t len2) { @@ -563,7 +566,7 @@ static int record__process_auxtrace(struct perf_tool *tool, } static int record__auxtrace_mmap_read(struct record *rec, - struct perf_mmap *map) + struct mmap *map) { int ret; @@ -579,7 +582,7 @@ static int record__auxtrace_mmap_read(struct record *rec, } static int record__auxtrace_mmap_read_snapshot(struct record *rec, - struct perf_mmap *map) + struct mmap *map) { int ret; @@ -600,8 +603,8 @@ static int record__auxtrace_read_snapshot_all(struct record *rec) int i; int rc = 0; - for (i = 0; i < rec->evlist->nr_mmaps; i++) { - struct perf_mmap *map = &rec->evlist->mmap[i]; + for (i = 0; i < rec->evlist->core.nr_mmaps; i++) { + struct mmap *map = &rec->evlist->mmap[i]; if (!map->auxtrace_mmap.base) continue; @@ -666,7 +669,7 @@ static int record__auxtrace_init(struct record *rec) static inline int record__auxtrace_mmap_read(struct record *rec __maybe_unused, - struct perf_mmap *map __maybe_unused) + struct mmap *map __maybe_unused) { return 0; } @@ -705,7 +708,7 @@ static int record__mmap_evlist(struct record *rec, if (opts->affinity != PERF_AFFINITY_SYS) cpu__setup_cpunode_map(); - if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, + if (evlist__mmap_ex(evlist, opts->mmap_pages, opts->auxtrace_mmap_pages, opts->auxtrace_snapshot_mode, opts->nr_cblocks, opts->affinity, @@ -753,9 +756,9 @@ static int record__open(struct record *rec) if (perf_evlist__add_dummy(evlist)) return -ENOMEM; - pos = perf_evlist__first(evlist); + pos = evlist__first(evlist); pos->tracking = 0; - pos = perf_evlist__last(evlist); + pos = evlist__last(evlist); pos->tracking = 1; pos->core.attr.enable_on_exec = 1; } @@ -786,6 +789,17 @@ try_again: pos->supported = true; } + if (symbol_conf.kptr_restrict && !perf_evlist__exclude_kernel(evlist)) { + pr_warning( +"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" +"check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n" +"Samples in kernel functions may not be resolved if a suitable vmlinux\n" +"file is not found in the buildid cache or in the vmlinux path.\n\n" +"Samples in kernel modules won't be resolved at all.\n\n" +"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" +"even with a suitable vmlinux or kallsyms file.\n\n"); + } + if (perf_evlist__apply_filters(evlist, &pos)) { pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", pos->filter, perf_evsel__name(pos), errno, @@ -888,7 +902,7 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static void record__adjust_affinity(struct record *rec, struct perf_mmap *map) +static void record__adjust_affinity(struct record *rec, struct mmap *map) { if (rec->opts.affinity != PERF_AFFINITY_SYS && !CPU_EQUAL(&rec->affinity_mask, &map->affinity_mask)) { @@ -935,7 +949,7 @@ static int record__mmap_read_evlist(struct record *rec, struct evlist *evlist, u64 bytes_written = rec->bytes_written; int i; int rc = 0; - struct perf_mmap *maps; + struct mmap *maps; int trace_fd = rec->data.file.fd; off_t off = 0; @@ -952,20 +966,20 @@ static int record__mmap_read_evlist(struct record *rec, struct evlist *evlist, if (record__aio_enabled(rec)) off = record__aio_get_pos(trace_fd); - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { u64 flush = 0; - struct perf_mmap *map = &maps[i]; + struct mmap *map = &maps[i]; - if (map->base) { + if (map->core.base) { record__adjust_affinity(rec, map); if (synch) { - flush = map->flush; - map->flush = 1; + flush = map->core.flush; + map->core.flush = 1; } if (!record__aio_enabled(rec)) { if (perf_mmap__push(map, rec, record__pushfn) < 0) { if (synch) - map->flush = flush; + map->core.flush = flush; rc = -1; goto out; } @@ -973,13 +987,13 @@ static int record__mmap_read_evlist(struct record *rec, struct evlist *evlist, if (record__aio_push(rec, map, &off) < 0) { record__aio_set_pos(trace_fd, off); if (synch) - map->flush = flush; + map->core.flush = flush; rc = -1; goto out; } } if (synch) - map->flush = flush; + map->core.flush = flush; } if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode && @@ -1180,23 +1194,14 @@ static void workload_exec_failed_signal(int signo __maybe_unused, static void snapshot_sig_handler(int sig); static void alarm_sig_handler(int sig); -int __weak -perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, - struct perf_tool *tool __maybe_unused, - perf_event__handler_t process __maybe_unused, - struct machine *machine __maybe_unused) -{ - return 0; -} - static const struct perf_event_mmap_page * perf_evlist__pick_pc(struct evlist *evlist) { if (evlist) { - if (evlist->mmap && evlist->mmap[0].base) - return evlist->mmap[0].base; - if (evlist->overwrite_mmap && evlist->overwrite_mmap[0].base) - return evlist->overwrite_mmap[0].base; + if (evlist->mmap && evlist->mmap[0].core.base) + return evlist->mmap[0].core.base; + if (evlist->overwrite_mmap && evlist->overwrite_mmap[0].core.base) + return evlist->overwrite_mmap[0].core.base; } return NULL; } @@ -1362,9 +1367,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } session = perf_session__new(data, false, tool); - if (session == NULL) { + if (IS_ERR(session)) { pr_err("Perf session creation failed.\n"); - return -1; + return PTR_ERR(session); } fd = perf_data__fd(data); @@ -1407,7 +1412,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) err = -1; goto out_child; } - session->header.env.comp_mmap_len = session->evlist->mmap_len; + session->header.env.comp_mmap_len = session->evlist->core.mmap_len; err = bpf__apply_obj_config(); if (err) { @@ -1610,7 +1615,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) if (hits == rec->samples) { if (done || draining) break; - err = perf_evlist__poll(rec->evlist, -1); + err = evlist__poll(rec->evlist, -1); /* * Propagate error, only if there's any. Ignore positive * number of returned events and interrupt error. @@ -1619,7 +1624,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) err = 0; waking++; - if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0) + if (evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0) draining = true; } @@ -1976,7 +1981,7 @@ out_free: static void switch_output_size_warn(struct record *rec) { - u64 wakeup_size = perf_evlist__mmap_size(rec->opts.mmap_pages); + u64 wakeup_size = evlist__mmap_size(rec->opts.mmap_pages); struct switch_output *s = &rec->switch_output; wakeup_size /= 2; @@ -2371,16 +2376,6 @@ int cmd_record(int argc, const char **argv) err = -ENOMEM; - if (symbol_conf.kptr_restrict && !perf_evlist__exclude_kernel(rec->evlist)) - pr_warning( -"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" -"check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n" -"Samples in kernel functions may not be resolved if a suitable vmlinux\n" -"file is not found in the buildid cache or in the vmlinux path.\n\n" -"Samples in kernel modules won't be resolved at all.\n\n" -"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" -"even with a suitable vmlinux or kallsyms file.\n\n"); - if (rec->no_buildid_cache || rec->no_buildid) { disable_buildid_cache(); } else if (rec->switch_output.enabled) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b18fab94d38d..aae0e57c60fb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -48,7 +48,7 @@ #include "util/auxtrace.h" #include "util/units.h" #include "util/branch.h" -#include "util/util.h" +#include "util/util.h" // perf_tip() #include "ui/ui.h" #include "ui/progress.h" @@ -1269,8 +1269,8 @@ int cmd_report(int argc, const char **argv) repeat: session = perf_session__new(&data, false, &report.tool); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); ret = evswitch__init(&report.evswitch, session->evlist, stderr); if (ret) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index ec96d64aec69..5cacc4f84c8d 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -3,8 +3,10 @@ #include "perf.h" #include "perf-sys.h" +#include "util/cpumap.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evsel_fprintf.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" @@ -23,6 +25,7 @@ #include "util/trace-event.h" #include "util/debug.h" +#include "util/event.h" #include <linux/kernel.h> #include <linux/log2.h> @@ -36,7 +39,9 @@ #include <pthread.h> #include <math.h> #include <api/fs/fs.h> +#include <perf/cpumap.h> #include <linux/time64.h> +#include <linux/err.h> #include <linux/ctype.h> @@ -1794,9 +1799,9 @@ static int perf_sched__read_events(struct perf_sched *sched) int rc = -1; session = perf_session__new(&data, false, &sched->tool); - if (session == NULL) { - pr_debug("No Memory for session\n"); - return -1; + if (IS_ERR(session)) { + pr_debug("Error creating perf session"); + return PTR_ERR(session); } symbol__init(&session->header.env); @@ -2051,7 +2056,7 @@ static void timehist_print_sample(struct perf_sched *sched, EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE | EVSEL__PRINT_CALLCHAIN_ARROW | EVSEL__PRINT_SKIP_IGNORED, - &callchain_cursor, stdout); + &callchain_cursor, symbol_conf.bt_stop_list, stdout); out: printf("\n"); @@ -2986,8 +2991,8 @@ static int perf_sched__timehist(struct perf_sched *sched) symbol_conf.use_callchain = sched->show_callchain; session = perf_session__new(&data, false, &sched->tool); - if (session == NULL) - return -ENOMEM; + if (IS_ERR(session)) + return PTR_ERR(session); evlist = session->evlist; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index e079b34201f2..286fc70d7402 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -17,6 +17,7 @@ #include "util/trace-event.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evsel_fprintf.h" #include "util/evswitch.h" #include "util/sort.h" #include "util/data.h" @@ -52,6 +53,7 @@ #include <unistd.h> #include <subcmd/pager.h> #include <perf/evlist.h> +#include <linux/err.h> #include "util/record.h" #include "util/util.h" #include "perf.h" @@ -1324,7 +1326,8 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample, } else printed += fprintf(fp, "\n"); - printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, fp); + printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, + symbol_conf.bt_stop_list, fp); } /* print branch_to information */ @@ -1866,7 +1869,8 @@ static void process_event(struct perf_script *script, cursor = &callchain_cursor; fputc(cursor ? '\n' : ' ', fp); - sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, fp); + sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, + symbol_conf.bt_stop_list, fp); } if (PRINT_FIELD(IREGS)) @@ -1915,7 +1919,7 @@ static void __process_stat(struct evsel *counter, u64 tstamp) int cpu, thread; static int header_printed; - if (counter->system_wide) + if (counter->core.system_wide) nthreads = 1; if (!header_printed) { @@ -2042,7 +2046,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, return err; evlist = *pevlist; - evsel = perf_evlist__last(*pevlist); + evsel = evlist__last(*pevlist); if (!evsel->priv) { if (scr->per_event_dump) { @@ -3083,8 +3087,8 @@ int find_scripts(char **scripts_array, char **scripts_path_array, int num, int i = 0; session = perf_session__new(&data, false, NULL); - if (!session) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path()); @@ -3754,8 +3758,8 @@ int cmd_script(int argc, const char **argv) } session = perf_session__new(&data, false, &script.tool); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); if (header || header_only) { script.tool.show_feat_hdr = SHOW_FEAT_HEADER; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 7e17bf9f700a..468fc49420ce 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -61,6 +61,7 @@ #include "util/tool.h" #include "util/string2.h" #include "util/metricgroup.h" +#include "util/synthetic-events.h" #include "util/target.h" #include "util/time-utils.h" #include "util/top.h" @@ -82,6 +83,7 @@ #include <unistd.h> #include <sys/time.h> #include <sys/resource.h> +#include <linux/err.h> #include <linux/ctype.h> #include <perf/evlist.h> @@ -233,7 +235,7 @@ static int write_stat_round_event(u64 tm, u64 type) #define WRITE_STAT_ROUND_EVENT(time, interval) \ write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval) -#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) +#define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y) static int perf_evsel__write_stat_event(struct evsel *counter, u32 cpu, u32 thread, @@ -276,7 +278,7 @@ static int read_counter(struct evsel *counter, struct timespec *rs) if (!counter->supported) return -ENOENT; - if (counter->system_wide) + if (counter->core.system_wide) nthreads = 1; for (thread = 0; thread < nthreads; thread++) { @@ -540,8 +542,8 @@ try_again: if (err < 0) return err; - err = perf_stat_synthesize_config(&stat_config, NULL, evsel_list, - process_synthesized_event, is_pipe); + err = perf_event__synthesize_stat_events(&stat_config, NULL, evsel_list, + process_synthesized_event, is_pipe); if (err < 0) return err; } @@ -822,18 +824,6 @@ static int perf_stat__get_core(struct perf_stat_config *config __maybe_unused, return cpu_map__get_core(map, cpu, NULL); } -static int cpu_map__get_max(struct perf_cpu_map *map) -{ - int i, max = -1; - - for (i = 0; i < map->nr; i++) { - if (map->map[i] > max) - max = map->map[i]; - } - - return max; -} - static int perf_stat__get_aggr(struct perf_stat_config *config, aggr_get_id_t get_id, struct perf_cpu_map *map, int idx) { @@ -928,7 +918,7 @@ static int perf_stat_init_aggr_mode(void) * taking the highest cpu number to be the size of * the aggregation translate cpumap. */ - nr = cpu_map__get_max(evsel_list->core.cpus); + nr = perf_cpu_map__max(evsel_list->core.cpus); stat_config.cpus_aggr_map = perf_cpu_map__empty_new(nr + 1); return stat_config.cpus_aggr_map ? 0 : -ENOMEM; } @@ -1447,9 +1437,9 @@ static int __cmd_record(int argc, const char **argv) } session = perf_session__new(data, false, NULL); - if (session == NULL) { - pr_err("Perf session creation failed.\n"); - return -1; + if (IS_ERR(session)) { + pr_err("Perf session creation failed\n"); + return PTR_ERR(session); } init_features(session); @@ -1646,8 +1636,8 @@ static int __cmd_report(int argc, const char **argv) perf_stat.data.mode = PERF_DATA_MODE_READ; session = perf_session__new(&perf_stat.data, false, &perf_stat.tool); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); perf_stat.session = session; stat_config.output = stderr; @@ -1681,7 +1671,7 @@ static void setup_system_wide(int forks) struct evsel *counter; evlist__for_each_entry(evsel_list, counter) { - if (!counter->system_wide) + if (!counter->core.system_wide) return; } @@ -1963,8 +1953,11 @@ int cmd_stat(int argc, const char **argv) fprintf(output, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); + if (run_idx != 0) + perf_evlist__reset_prev_raw_counts(evsel_list); + status = run_perf_stat(argc, argv, run_idx); - if (forever && status != -1) { + if (forever && status != -1 && !interval) { print_counters(NULL, argc, argv); perf_stat__reset_stats(); } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index e0e822695a29..9e84fae9b096 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -35,6 +35,7 @@ #include "util/tool.h" #include "util/data.h" #include "util/debug.h" +#include <linux/err.h> #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE FILE *open_memstream(char **ptr, size_t *sizeloc); @@ -1601,8 +1602,8 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) &tchart->tool); int ret = -EINVAL; - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); symbol__init(&session->header.env); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 726e3f2dd8c7..1f60124eb19b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -27,11 +27,14 @@ #include "util/dso.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evsel_config.h" #include "util/event.h" #include "util/machine.h" #include "util/map.h" +#include "util/mmap.h" #include "util/session.h" #include "util/symbol.h" +#include "util/synthetic-events.h" #include "util/top.h" #include "util/util.h" #include <linux/rbtree.h> @@ -76,6 +79,7 @@ #include <linux/stringify.h> #include <linux/time64.h> #include <linux/types.h> +#include <linux/err.h> #include <linux/ctype.h> @@ -528,7 +532,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) prompt_integer(&counter, "Enter details event counter"); if (counter >= top->evlist->core.nr_entries) { - top->sym_evsel = perf_evlist__first(top->evlist); + top->sym_evsel = evlist__first(top->evlist); fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel)); sleep(1); break; @@ -537,7 +541,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) if (top->sym_evsel->idx == counter) break; } else - top->sym_evsel = perf_evlist__first(top->evlist); + top->sym_evsel = evlist__first(top->evlist); break; case 'f': prompt_integer(&top->count_filter, "Enter display event count filter"); @@ -861,7 +865,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) { struct record_opts *opts = &top->record_opts; struct evlist *evlist = top->evlist; - struct perf_mmap *md; + struct mmap *md; union perf_event *event; md = opts->overwrite ? &evlist->overwrite_mmap[idx] : &evlist->mmap[idx]; @@ -901,7 +905,7 @@ static void perf_top__mmap_read(struct perf_top *top) if (overwrite) perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_DATA_PENDING); - for (i = 0; i < top->evlist->nr_mmaps; i++) + for (i = 0; i < top->evlist->core.nr_mmaps; i++) perf_top__mmap_read_idx(top, i); if (overwrite) { @@ -959,7 +963,7 @@ static int perf_top__overwrite_check(struct perf_top *top) /* has term for current event */ if ((overwrite < 0) && (set >= 0)) { /* if it's first event, set overwrite */ - if (evsel == perf_evlist__first(evlist)) + if (evsel == evlist__first(evlist)) overwrite = set; else return -1; @@ -983,7 +987,7 @@ static int perf_top_overwrite_fallback(struct perf_top *top, return 0; /* only fall back when first event fails */ - if (evsel != perf_evlist__first(evlist)) + if (evsel != evlist__first(evlist)) return 0; evlist__for_each_entry(evlist, counter) @@ -1040,7 +1044,7 @@ try_again: } } - if (perf_evlist__mmap(evlist, opts->mmap_pages) < 0) { + if (evlist__mmap(evlist, opts->mmap_pages) < 0) { ui__error("Failed to mmap with %d (%s)\n", errno, str_error_r(errno, msg, sizeof(msg))); goto out_err; @@ -1304,7 +1308,7 @@ static int __cmd_top(struct perf_top *top) } /* Wait for a minimal set of events before starting the snapshot */ - perf_evlist__poll(top->evlist, 100); + evlist__poll(top->evlist, 100); perf_top__mmap_read(top); @@ -1314,7 +1318,7 @@ static int __cmd_top(struct perf_top *top) perf_top__mmap_read(top); if (opts->overwrite || (hits == top->samples)) - ret = perf_evlist__poll(top->evlist, 100); + ret = evlist__poll(top->evlist, 100); if (resize) { perf_top__resize(top); @@ -1641,7 +1645,7 @@ int cmd_top(int argc, const char **argv) goto out_delete_evlist; } - top.sym_evsel = perf_evlist__first(top.evlist); + top.sym_evsel = evlist__first(top.evlist); if (!callchain_param.enabled) { symbol_conf.cumulate_callchain = false; @@ -1671,8 +1675,8 @@ int cmd_top(int argc, const char **argv) } top.session = perf_session__new(NULL, false, NULL); - if (top.session == NULL) { - status = -1; + if (IS_ERR(top.session)) { + status = PTR_ERR(top.session); goto out_delete_evlist; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 0f633f0d6be8..bb5130d02155 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -28,8 +28,12 @@ #include "util/dso.h" #include "util/env.h" #include "util/event.h" +#include "util/evsel.h" +#include "util/evsel_fprintf.h" +#include "util/synthetic-events.h" #include "util/evlist.h" #include "util/evswitch.h" +#include "util/mmap.h" #include <subcmd/pager.h> #include <subcmd/exec-cmd.h> #include "util/machine.h" @@ -2074,7 +2078,7 @@ static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sam EVSEL__PRINT_DSO | EVSEL__PRINT_UNKNOWN_AS_ADDR; - return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output); + return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, symbol_conf.bt_stop_list, trace->output); } static const char *errno_to_name(struct evsel *evsel, int err) @@ -3408,7 +3412,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (trace->dump.map) bpf_map__fprintf(trace->dump.map, trace->output); - err = perf_evlist__mmap(evlist, trace->opts.mmap_pages); + err = evlist__mmap(evlist, trace->opts.mmap_pages); if (err < 0) goto out_error_mmap; @@ -3425,7 +3429,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) trace->multiple_threads = perf_thread_map__pid(evlist->core.threads, 0) == -1 || evlist->core.threads->nr > 1 || - perf_evlist__first(evlist)->core.attr.inherit; + evlist__first(evlist)->core.attr.inherit; /* * Now that we already used evsel->core.attr to ask the kernel to setup the @@ -3441,9 +3445,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv) again: before = trace->nr_events; - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { union perf_event *event; - struct perf_mmap *md; + struct mmap *md; md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) @@ -3472,8 +3476,8 @@ again: if (trace->nr_events == before) { int timeout = done ? 100 : -1; - if (!draining && perf_evlist__poll(evlist, timeout) > 0) { - if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0) + if (!draining && evlist__poll(evlist, timeout) > 0) { + if (evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0) draining = true; goto again; @@ -3584,8 +3588,8 @@ static int trace__replay(struct trace *trace) trace->multiple_threads = true; session = perf_session__new(&data, false, &trace->tool); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); if (trace->opts.target.pid) symbol_conf.pid_list_str = strdup(trace->opts.target.pid); diff --git a/tools/perf/jvmti/Build b/tools/perf/jvmti/Build index eaeb8cb5379b..1e148bbdf820 100644 --- a/tools/perf/jvmti/Build +++ b/tools/perf/jvmti/Build @@ -1,8 +1,17 @@ jvmti-y += libjvmti.o jvmti-y += jvmti_agent.o +# For strlcpy +jvmti-y += libstring.o + CFLAGS_jvmti = -fPIC -DPIC -I$(JDIR)/include -I$(JDIR)/include/linux CFLAGS_REMOVE_jvmti = -Wmissing-declarations CFLAGS_REMOVE_jvmti += -Wstrict-prototypes CFLAGS_REMOVE_jvmti += -Wextra CFLAGS_REMOVE_jvmti += -Wwrite-strings + +CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" + +$(OUTPUT)jvmti/libstring.o: ../lib/string.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/lib/Makefile b/tools/perf/lib/Makefile index a67efb8d9d39..85ccb8c439a4 100644 --- a/tools/perf/lib/Makefile +++ b/tools/perf/lib/Makefile @@ -59,7 +59,13 @@ else CFLAGS := -g -Wall endif -INCLUDES = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(SRCARCH)/include/ -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi -I$(srctree)/tools/include/uapi +INCLUDES = \ +-I$(srctree)/tools/perf/lib/include \ +-I$(srctree)/tools/lib/ \ +-I$(srctree)/tools/include \ +-I$(srctree)/tools/arch/$(SRCARCH)/include/ \ +-I$(srctree)/tools/arch/$(SRCARCH)/include/uapi \ +-I$(srctree)/tools/include/uapi # Append required CFLAGS override CFLAGS += $(EXTRA_WARNINGS) @@ -88,13 +94,34 @@ LIBPERF_PC := $(OUTPUT)libperf.pc LIBPERF_ALL := $(LIBPERF_A) $(OUTPUT)libperf.so* +LIB_DIR := $(srctree)/tools/lib/api/ + +ifneq ($(OUTPUT),) +ifneq ($(subdir),) + API_PATH=$(OUTPUT)/../lib/api/ +else + API_PATH=$(OUTPUT) +endif +else + API_PATH=$(LIB_DIR) +endif + +LIBAPI = $(API_PATH)libapi.a + +$(LIBAPI): FORCE + $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a + +$(LIBAPI)-clean: + $(call QUIET_CLEAN, libapi) + $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null + $(LIBPERF_IN): FORCE $(Q)$(MAKE) $(build)=libperf $(LIBPERF_A): $(LIBPERF_IN) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) -$(LIBPERF_SO): $(LIBPERF_IN) +$(LIBPERF_SO): $(LIBPERF_IN) $(LIBAPI) $(QUIET_LINK)$(CC) --shared -Wl,-soname,libperf.so \ -Wl,--version-script=$(VERSION_SCRIPT) $^ -o $@ @ln -sf $(@F) $(OUTPUT)libperf.so @@ -106,12 +133,12 @@ libs: $(LIBPERF_A) $(LIBPERF_SO) $(LIBPERF_PC) all: fixdep $(Q)$(MAKE) libs -clean: +clean: $(LIBAPI)-clean $(call QUIET_CLEAN, libperf) $(RM) $(LIBPERF_A) \ *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBPERF_VERSION) .*.d .*.cmd LIBPERF-CFLAGS $(LIBPERF_PC) $(Q)$(MAKE) -C tests clean -tests: +tests: libs $(Q)$(MAKE) -C tests $(Q)$(MAKE) -C tests run @@ -146,6 +173,7 @@ install_headers: $(call do_install,include/perf/threadmap.h,$(prefix)/include/perf,644); \ $(call do_install,include/perf/evlist.h,$(prefix)/include/perf,644); \ $(call do_install,include/perf/evsel.h,$(prefix)/include/perf,644); + $(call do_install,include/perf/event.h,$(prefix)/include/perf,644); install_pkgconfig: $(LIBPERF_PC) $(call QUIET_INSTALL, $(LIBPERF_PC)) \ diff --git a/tools/perf/lib/core.c b/tools/perf/lib/core.c index 29d5e3348718..d0b9ae422b9f 100644 --- a/tools/perf/lib/core.c +++ b/tools/perf/lib/core.c @@ -4,7 +4,9 @@ #include <stdio.h> #include <stdarg.h> +#include <unistd.h> #include <perf/core.h> +#include <internal/lib.h> #include "internal.h" static int __base_pr(enum libperf_print_level level, const char *format, @@ -15,11 +17,6 @@ static int __base_pr(enum libperf_print_level level, const char *format, static libperf_print_fn_t __libperf_pr = __base_pr; -void libperf_set_print(libperf_print_fn_t fn) -{ - __libperf_pr = fn; -} - __printf(2, 3) void libperf_print(enum libperf_print_level level, const char *format, ...) { @@ -32,3 +29,9 @@ void libperf_print(enum libperf_print_level level, const char *format, ...) __libperf_pr(level, format, args); va_end(args); } + +void libperf_init(libperf_print_fn_t fn) +{ + page_size = sysconf(_SC_PAGE_SIZE); + __libperf_pr = fn; +} diff --git a/tools/perf/lib/cpumap.c b/tools/perf/lib/cpumap.c index 1f0e6f334237..2ca1fafa620d 100644 --- a/tools/perf/lib/cpumap.c +++ b/tools/perf/lib/cpumap.c @@ -260,3 +260,15 @@ int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu) return -1; } + +int perf_cpu_map__max(struct perf_cpu_map *map) +{ + int i, max = -1; + + for (i = 0; i < map->nr; i++) { + if (map->map[i] > max) + max = map->map[i]; + } + + return max; +} diff --git a/tools/perf/lib/evlist.c b/tools/perf/lib/evlist.c index f4dc9a208332..d1496fee810c 100644 --- a/tools/perf/lib/evlist.c +++ b/tools/perf/lib/evlist.c @@ -1,16 +1,30 @@ // SPDX-License-Identifier: GPL-2.0 #include <perf/evlist.h> #include <perf/evsel.h> +#include <linux/bitops.h> #include <linux/list.h> +#include <linux/hash.h> +#include <sys/ioctl.h> #include <internal/evlist.h> #include <internal/evsel.h> +#include <internal/xyarray.h> #include <linux/zalloc.h> #include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <poll.h> #include <perf/cpumap.h> #include <perf/threadmap.h> +#include <api/fd/array.h> void perf_evlist__init(struct perf_evlist *evlist) { + int i; + + for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) + INIT_HLIST_HEAD(&evlist->heads[i]); INIT_LIST_HEAD(&evlist->entries); evlist->nr_entries = 0; } @@ -157,3 +171,113 @@ void perf_evlist__disable(struct perf_evlist *evlist) perf_evlist__for_each_entry(evlist, evsel) perf_evsel__disable(evsel); } + +u64 perf_evlist__read_format(struct perf_evlist *evlist) +{ + struct perf_evsel *first = perf_evlist__first(evlist); + + return first->attr.read_format; +} + +#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) + +static void perf_evlist__id_hash(struct perf_evlist *evlist, + struct perf_evsel *evsel, + int cpu, int thread, u64 id) +{ + int hash; + struct perf_sample_id *sid = SID(evsel, cpu, thread); + + sid->id = id; + sid->evsel = evsel; + hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); + hlist_add_head(&sid->node, &evlist->heads[hash]); +} + +void perf_evlist__id_add(struct perf_evlist *evlist, + struct perf_evsel *evsel, + int cpu, int thread, u64 id) +{ + perf_evlist__id_hash(evlist, evsel, cpu, thread, id); + evsel->id[evsel->ids++] = id; +} + +int perf_evlist__id_add_fd(struct perf_evlist *evlist, + struct perf_evsel *evsel, + int cpu, int thread, int fd) +{ + u64 read_data[4] = { 0, }; + int id_idx = 1; /* The first entry is the counter value */ + u64 id; + int ret; + + ret = ioctl(fd, PERF_EVENT_IOC_ID, &id); + if (!ret) + goto add; + + if (errno != ENOTTY) + return -1; + + /* Legacy way to get event id.. All hail to old kernels! */ + + /* + * This way does not work with group format read, so bail + * out in that case. + */ + if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) + return -1; + + if (!(evsel->attr.read_format & PERF_FORMAT_ID) || + read(fd, &read_data, sizeof(read_data)) == -1) + return -1; + + if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + ++id_idx; + if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + ++id_idx; + + id = read_data[id_idx]; + +add: + perf_evlist__id_add(evlist, evsel, cpu, thread, id); + return 0; +} + +int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) +{ + int nr_cpus = perf_cpu_map__nr(evlist->cpus); + int nr_threads = perf_thread_map__nr(evlist->threads); + int nfds = 0; + struct perf_evsel *evsel; + + perf_evlist__for_each_entry(evlist, evsel) { + if (evsel->system_wide) + nfds += nr_cpus; + else + nfds += nr_cpus * nr_threads; + } + + if (fdarray__available_entries(&evlist->pollfd) < nfds && + fdarray__grow(&evlist->pollfd, nfds) < 0) + return -ENOMEM; + + return 0; +} + +int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, + void *ptr, short revent) +{ + int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); + + if (pos >= 0) { + evlist->pollfd.priv[pos].ptr = ptr; + fcntl(fd, F_SETFL, O_NONBLOCK); + } + + return pos; +} + +int perf_evlist__poll(struct perf_evlist *evlist, int timeout) +{ + return fdarray__poll(&evlist->pollfd, timeout); +} diff --git a/tools/perf/lib/evsel.c b/tools/perf/lib/evsel.c index 24abc80dd767..a8cb582e2721 100644 --- a/tools/perf/lib/evsel.c +++ b/tools/perf/lib/evsel.c @@ -230,3 +230,33 @@ struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel) { return &evsel->attr; } + +int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) +{ + if (ncpus == 0 || nthreads == 0) + return 0; + + if (evsel->system_wide) + nthreads = 1; + + evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); + if (evsel->sample_id == NULL) + return -ENOMEM; + + evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); + if (evsel->id == NULL) { + xyarray__delete(evsel->sample_id); + evsel->sample_id = NULL; + return -ENOMEM; + } + + return 0; +} + +void perf_evsel__free_id(struct perf_evsel *evsel) +{ + xyarray__delete(evsel->sample_id); + evsel->sample_id = NULL; + zfree(&evsel->id); + evsel->ids = 0; +} diff --git a/tools/perf/lib/include/internal/evlist.h b/tools/perf/lib/include/internal/evlist.h index 448891f06e3e..9f440ab12b76 100644 --- a/tools/perf/lib/include/internal/evlist.h +++ b/tools/perf/lib/include/internal/evlist.h @@ -3,6 +3,11 @@ #define __LIBPERF_INTERNAL_EVLIST_H #include <linux/list.h> +#include <api/fd/array.h> +#include <internal/evsel.h> + +#define PERF_EVLIST__HLIST_BITS 8 +#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) struct perf_cpu_map; struct perf_thread_map; @@ -13,8 +18,16 @@ struct perf_evlist { bool has_user_cpus; struct perf_cpu_map *cpus; struct perf_thread_map *threads; + int nr_mmaps; + size_t mmap_len; + struct fdarray pollfd; + struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; }; +int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); +int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, + void *ptr, short revent); + /** * __perf_evlist__for_each_entry - iterate thru all the evsels * @list: list_head instance to iterate @@ -47,4 +60,24 @@ struct perf_evlist { #define perf_evlist__for_each_entry_reverse(evlist, evsel) \ __perf_evlist__for_each_entry_reverse(&(evlist)->entries, evsel) +static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) +{ + return list_entry(evlist->entries.next, struct perf_evsel, node); +} + +static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) +{ + return list_entry(evlist->entries.prev, struct perf_evsel, node); +} + +u64 perf_evlist__read_format(struct perf_evlist *evlist); + +void perf_evlist__id_add(struct perf_evlist *evlist, + struct perf_evsel *evsel, + int cpu, int thread, u64 id); + +int perf_evlist__id_add_fd(struct perf_evlist *evlist, + struct perf_evsel *evsel, + int cpu, int thread, int fd); + #endif /* __LIBPERF_INTERNAL_EVLIST_H */ diff --git a/tools/perf/lib/include/internal/evsel.h b/tools/perf/lib/include/internal/evsel.h index 8b854d1c9b45..a69b8299c36f 100644 --- a/tools/perf/lib/include/internal/evsel.h +++ b/tools/perf/lib/include/internal/evsel.h @@ -4,9 +4,35 @@ #include <linux/types.h> #include <linux/perf_event.h> +#include <stdbool.h> +#include <sys/types.h> struct perf_cpu_map; struct perf_thread_map; +struct xyarray; + +/* + * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are + * more than one entry in the evlist. + */ +struct perf_sample_id { + struct hlist_node node; + u64 id; + struct perf_evsel *evsel; + /* + * 'idx' will be used for AUX area sampling. A sample will have AUX area + * data that will be queued for decoding, where there are separate + * queues for each CPU (per-cpu tracing) or task (per-thread tracing). + * The sample ID can be used to lookup 'idx' which is effectively the + * queue number. + */ + int idx; + int cpu; + pid_t tid; + + /* Holds total ID period value for PERF_SAMPLE_READ processing. */ + u64 period; +}; struct perf_evsel { struct list_head node; @@ -15,9 +41,13 @@ struct perf_evsel { struct perf_cpu_map *own_cpus; struct perf_thread_map *threads; struct xyarray *fd; + struct xyarray *sample_id; + u64 *id; + u32 ids; /* parse modifier helper */ int nr_members; + bool system_wide; }; int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); @@ -26,4 +56,7 @@ void perf_evsel__free_fd(struct perf_evsel *evsel); int perf_evsel__read_size(struct perf_evsel *evsel); int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter); +int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); +void perf_evsel__free_id(struct perf_evsel *evsel); + #endif /* __LIBPERF_INTERNAL_EVSEL_H */ diff --git a/tools/perf/lib/include/internal/lib.h b/tools/perf/lib/include/internal/lib.h index 0b56f1201dc9..5175d491b2d4 100644 --- a/tools/perf/lib/include/internal/lib.h +++ b/tools/perf/lib/include/internal/lib.h @@ -2,7 +2,9 @@ #ifndef __LIBPERF_INTERNAL_LIB_H #define __LIBPERF_INTERNAL_LIB_H -#include <unistd.h> +#include <sys/types.h> + +extern unsigned int page_size; ssize_t readn(int fd, void *buf, size_t n); ssize_t writen(int fd, const void *buf, size_t n); diff --git a/tools/perf/lib/include/internal/mmap.h b/tools/perf/lib/include/internal/mmap.h new file mode 100644 index 000000000000..ba1e519c15b9 --- /dev/null +++ b/tools/perf/lib/include/internal/mmap.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBPERF_INTERNAL_MMAP_H +#define __LIBPERF_INTERNAL_MMAP_H + +#include <linux/compiler.h> +#include <linux/refcount.h> +#include <linux/types.h> +#include <stdbool.h> + +/* perf sample has 16 bits size limit */ +#define PERF_SAMPLE_MAX_SIZE (1 << 16) + +/** + * struct perf_mmap - perf's ring buffer mmap details + * + * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this + */ +struct perf_mmap { + void *base; + int mask; + int fd; + int cpu; + refcount_t refcnt; + u64 prev; + u64 start; + u64 end; + bool overwrite; + u64 flush; + char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); +}; + +#endif /* __LIBPERF_INTERNAL_MMAP_H */ diff --git a/tools/perf/lib/include/perf/core.h b/tools/perf/lib/include/perf/core.h index c341a7b2c874..cfd70e720c1c 100644 --- a/tools/perf/lib/include/perf/core.h +++ b/tools/perf/lib/include/perf/core.h @@ -17,6 +17,6 @@ enum libperf_print_level { typedef int (*libperf_print_fn_t)(enum libperf_print_level level, const char *, va_list ap); -LIBPERF_API void libperf_set_print(libperf_print_fn_t fn); +LIBPERF_API void libperf_init(libperf_print_fn_t fn); #endif /* __LIBPERF_CORE_H */ diff --git a/tools/perf/lib/include/perf/cpumap.h b/tools/perf/lib/include/perf/cpumap.h index 8aa995c59498..ac9aa497f84a 100644 --- a/tools/perf/lib/include/perf/cpumap.h +++ b/tools/perf/lib/include/perf/cpumap.h @@ -16,6 +16,7 @@ LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map); LIBPERF_API int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx); LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus); LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map); +LIBPERF_API int perf_cpu_map__max(struct perf_cpu_map *map); #define perf_cpu_map__for_each_cpu(cpu, idx, cpus) \ for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx); \ diff --git a/tools/perf/lib/include/perf/evlist.h b/tools/perf/lib/include/perf/evlist.h index 38365f8f3fba..8a2ce0757ab2 100644 --- a/tools/perf/lib/include/perf/evlist.h +++ b/tools/perf/lib/include/perf/evlist.h @@ -31,5 +31,6 @@ LIBPERF_API void perf_evlist__disable(struct perf_evlist *evlist); LIBPERF_API void perf_evlist__set_maps(struct perf_evlist *evlist, struct perf_cpu_map *cpus, struct perf_thread_map *threads); +LIBPERF_API int perf_evlist__poll(struct perf_evlist *evlist, int timeout); #endif /* __LIBPERF_EVLIST_H */ diff --git a/tools/perf/lib/lib.c b/tools/perf/lib/lib.c index 2a81819c3b8c..18658931fc71 100644 --- a/tools/perf/lib/lib.c +++ b/tools/perf/lib/lib.c @@ -5,6 +5,8 @@ #include <linux/kernel.h> #include <internal/lib.h> +unsigned int page_size; + static ssize_t ion(bool is_read, int fd, void *buf, size_t n) { void *buf_start = buf; diff --git a/tools/perf/lib/libperf.map b/tools/perf/lib/libperf.map index dc4d66363bc4..ab8dbde1136c 100644 --- a/tools/perf/lib/libperf.map +++ b/tools/perf/lib/libperf.map @@ -1,6 +1,6 @@ LIBPERF_0.0.1 { global: - libperf_set_print; + libperf_init; perf_cpu_map__dummy_new; perf_cpu_map__get; perf_cpu_map__put; @@ -9,6 +9,7 @@ LIBPERF_0.0.1 { perf_cpu_map__nr; perf_cpu_map__cpu; perf_cpu_map__empty; + perf_cpu_map__max; perf_thread_map__new_dummy; perf_thread_map__set_pid; perf_thread_map__comm; @@ -38,6 +39,7 @@ LIBPERF_0.0.1 { perf_evlist__remove; perf_evlist__next; perf_evlist__set_maps; + perf_evlist__poll; local: *; }; diff --git a/tools/perf/lib/tests/test-cpumap.c b/tools/perf/lib/tests/test-cpumap.c index 76a43cfb83a1..aa34c20df07e 100644 --- a/tools/perf/lib/tests/test-cpumap.c +++ b/tools/perf/lib/tests/test-cpumap.c @@ -1,13 +1,23 @@ // SPDX-License-Identifier: GPL-2.0 +#include <stdarg.h> +#include <stdio.h> #include <perf/cpumap.h> #include <internal/tests.h> +static int libperf_print(enum libperf_print_level level, + const char *fmt, va_list ap) +{ + return vfprintf(stderr, fmt, ap); +} + int main(int argc, char **argv) { struct perf_cpu_map *cpus; __T_START; + libperf_init(libperf_print); + cpus = perf_cpu_map__dummy_new(); if (!cpus) return -1; diff --git a/tools/perf/lib/tests/test-evlist.c b/tools/perf/lib/tests/test-evlist.c index 4e1407f20ffd..e6b2ab2e2bde 100644 --- a/tools/perf/lib/tests/test-evlist.c +++ b/tools/perf/lib/tests/test-evlist.c @@ -1,4 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <stdarg.h> #include <linux/perf_event.h> #include <perf/cpumap.h> #include <perf/threadmap.h> @@ -6,6 +8,12 @@ #include <perf/evsel.h> #include <internal/tests.h> +static int libperf_print(enum libperf_print_level level, + const char *fmt, va_list ap) +{ + return vfprintf(stderr, fmt, ap); +} + static int test_stat_cpu(void) { struct perf_cpu_map *cpus; @@ -177,6 +185,8 @@ int main(int argc, char **argv) { __T_START; + libperf_init(libperf_print); + test_stat_cpu(); test_stat_thread(); test_stat_thread_enable(); diff --git a/tools/perf/lib/tests/test-evsel.c b/tools/perf/lib/tests/test-evsel.c index 2c648fe5617e..1b6c4285ac2b 100644 --- a/tools/perf/lib/tests/test-evsel.c +++ b/tools/perf/lib/tests/test-evsel.c @@ -1,10 +1,18 @@ // SPDX-License-Identifier: GPL-2.0 +#include <stdarg.h> +#include <stdio.h> #include <linux/perf_event.h> #include <perf/cpumap.h> #include <perf/threadmap.h> #include <perf/evsel.h> #include <internal/tests.h> +static int libperf_print(enum libperf_print_level level, + const char *fmt, va_list ap) +{ + return vfprintf(stderr, fmt, ap); +} + static int test_stat_cpu(void) { struct perf_cpu_map *cpus; @@ -116,6 +124,8 @@ int main(int argc, char **argv) { __T_START; + libperf_init(libperf_print); + test_stat_cpu(); test_stat_thread(); test_stat_thread_enable(); diff --git a/tools/perf/lib/tests/test-threadmap.c b/tools/perf/lib/tests/test-threadmap.c index 10a4f4cbbdd5..8c5f47247d9e 100644 --- a/tools/perf/lib/tests/test-threadmap.c +++ b/tools/perf/lib/tests/test-threadmap.c @@ -1,13 +1,23 @@ // SPDX-License-Identifier: GPL-2.0 +#include <stdarg.h> +#include <stdio.h> #include <perf/threadmap.h> #include <internal/tests.h> +static int libperf_print(enum libperf_print_level level, + const char *fmt, va_list ap) +{ + return vfprintf(stderr, fmt, ap); +} + int main(int argc, char **argv) { struct perf_thread_map *threads; __T_START; + libperf_init(libperf_print); + threads = perf_thread_map__new_dummy(); if (!threads) return -1; diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 1193b923e801..27f94b0bb874 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -12,6 +12,7 @@ #include "util/build-id.h" #include "util/cache.h" #include "util/env.h" +#include <internal/lib.h> // page_size #include <subcmd/exec-cmd.h> #include "util/config.h" #include <subcmd/run-command.h> @@ -20,11 +21,12 @@ #include "util/bpf-loader.h" #include "util/debug.h" #include "util/event.h" -#include "util/util.h" +#include "util/util.h" // usage() #include "ui/ui.h" #include "perf-sys.h" #include <api/fs/fs.h> #include <api/fs/tracing_path.h> +#include <perf/core.h> #include <errno.h> #include <pthread.h> #include <signal.h> @@ -428,6 +430,12 @@ void pthread__unblock_sigwinch(void) pthread_sigmask(SIG_UNBLOCK, &set, NULL); } +static int libperf_print(enum libperf_print_level level, + const char *fmt, va_list ap) +{ + return eprintf(level, verbose, fmt, ap); +} + int main(int argc, const char **argv) { int err; @@ -438,8 +446,7 @@ int main(int argc, const char **argv) exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); pager_init(PERF_PAGER_ENVIRONMENT); - /* The page_size is placed in util object. */ - page_size = sysconf(_SC_PAGE_SIZE); + libperf_init(libperf_print); cmd = extract_argv0_path(argv[0]); if (!cmd) diff --git a/tools/perf/pmu-events/README b/tools/perf/pmu-events/README index e62b09b6a844..de7efa2cebd1 100644 --- a/tools/perf/pmu-events/README +++ b/tools/perf/pmu-events/README @@ -30,9 +30,9 @@ the topic. Eg: "Floating-point.json". All the topic JSON files for a CPU model/family should be in a separate sub directory. Thus for the Silvermont X86 CPU: - $ ls tools/perf/pmu-events/arch/x86/Silvermont_core - Cache.json Memory.json Virtual-Memory.json - Frontend.json Pipeline.json + $ ls tools/perf/pmu-events/arch/x86/silvermont + cache.json memory.json virtual-memory.json + frontend.json pipeline.json The JSONs folder for a CPU model/family may be placed in the root arch folder, or may be placed in a vendor sub-folder under the arch folder @@ -94,7 +94,7 @@ users to specify events by their name: where 'pm_1plus_ppc_cmpl' is a Power8 PMU event. -However some errors in processing may cause the perf build to fail. +However some errors in processing may cause the alias build to fail. Mapfile format =============== @@ -119,7 +119,7 @@ where: Header line The header line is the first line in the file, which is - always _IGNORED_. It can empty. + always _IGNORED_. It can be empty. CPUID: CPUID is an arch-specific char string, that can be used @@ -138,15 +138,15 @@ where: files, relative to the directory containing the mapfile.csv Type: - indicates whether the events or "core" or "uncore" events. + indicates whether the events are "core" or "uncore" events. Eg: - $ grep Silvermont tools/perf/pmu-events/arch/x86/mapfile.csv - GenuineIntel-6-37,V13,Silvermont_core,core - GenuineIntel-6-4D,V13,Silvermont_core,core - GenuineIntel-6-4C,V13,Silvermont_core,core + $ grep silvermont tools/perf/pmu-events/arch/x86/mapfile.csv + GenuineIntel-6-37,v13,silvermont,core + GenuineIntel-6-4D,v13,silvermont,core + GenuineIntel-6-4C,v13,silvermont,core i.e the three CPU models use the JSON files (i.e PMU events) listed - in the directory 'tools/perf/pmu-events/arch/x86/Silvermont_core'. + in the directory 'tools/perf/pmu-events/arch/x86/silvermont'. diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/branch.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/branch.json new file mode 100644 index 000000000000..b5e5d055c70d --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/branch.json @@ -0,0 +1,14 @@ +[ + { + "PublicDescription": "Mispredicted or not predicted branch speculatively executed. This event counts any predictable branch instruction which is mispredicted either due to dynamic misprediction or because the MMU is off and the branches are statically predicted not taken.", + "EventCode": "0x10", + "EventName": "BR_MIS_PRED", + "BriefDescription": "Mispredicted or not predicted branch speculatively executed." + }, + { + "PublicDescription": "Predictable branch speculatively executed. This event counts all predictable branches.", + "EventCode": "0x12", + "EventName": "BR_PRED", + "BriefDescription": "Predictable branch speculatively executed." + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/bus.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/bus.json new file mode 100644 index 000000000000..fce7309ae624 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/bus.json @@ -0,0 +1,24 @@ +[ + { + "EventCode": "0x11", + "EventName": "CPU_CYCLES", + "BriefDescription": "The number of core clock cycles." + }, + { + "PublicDescription": "Bus access. This event counts for every beat of data transferred over the data channels between the core and the SCU. If both read and write data beats are transferred on a given cycle, this event is counted twice on that cycle. This event counts the sum of BUS_ACCESS_RD and BUS_ACCESS_WR.", + "EventCode": "0x19", + "EventName": "BUS_ACCESS", + "BriefDescription": "Bus access." + }, + { + "EventCode": "0x1D", + "EventName": "BUS_CYCLES", + "BriefDescription": "Bus cycles. This event duplicates CPU_CYCLES." + }, + { + "ArchStdEvent": "BUS_ACCESS_RD" + }, + { + "ArchStdEvent": "BUS_ACCESS_WR" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/cache.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/cache.json new file mode 100644 index 000000000000..24594081c199 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/cache.json @@ -0,0 +1,207 @@ +[ + { + "PublicDescription": "L1 instruction cache refill. This event counts any instruction fetch which misses in the cache.", + "EventCode": "0x01", + "EventName": "L1I_CACHE_REFILL", + "BriefDescription": "L1 instruction cache refill" + }, + { + "PublicDescription": "L1 instruction TLB refill. This event counts any refill of the instruction L1 TLB from the L2 TLB. This includes refills that result in a translation fault.", + "EventCode": "0x02", + "EventName": "L1I_TLB_REFILL", + "BriefDescription": "L1 instruction TLB refill" + }, + { + "PublicDescription": "L1 data cache refill. This event counts any load or store operation or page table walk access which causes data to be read from outside the L1, including accesses which do not allocate into L1.", + "EventCode": "0x03", + "EventName": "L1D_CACHE_REFILL", + "BriefDescription": "L1 data cache refill" + }, + { + "PublicDescription": "L1 data cache access. This event counts any load or store operation or page table walk access which looks up in the L1 data cache. In particular, any access which could count the L1D_CACHE_REFILL event causes this event to count.", + "EventCode": "0x04", + "EventName": "L1D_CACHE", + "BriefDescription": "L1 data cache access" + }, + { + "PublicDescription": "L1 data TLB refill. This event counts any refill of the data L1 TLB from the L2 TLB. This includes refills that result in a translation fault.", + "EventCode": "0x05", + "EventName": "L1D_TLB_REFILL", + "BriefDescription": "L1 data TLB refill" + }, + { + "PublicDescription": "Level 1 instruction cache access or Level 0 Macro-op cache access. This event counts any instruction fetch which accesses the L1 instruction cache or L0 Macro-op cache.", + "EventCode": "0x14", + "EventName": "L1I_CACHE", + "BriefDescription": "L1 instruction cache access" + }, + { + "PublicDescription": "L1 data cache Write-Back. This event counts any write-back of data from the L1 data cache to L2 or L3. This counts both victim line evictions and snoops, including cache maintenance operations.", + "EventCode": "0x15", + "EventName": "L1D_CACHE_WB", + "BriefDescription": "L1 data cache Write-Back" + }, + { + "PublicDescription": "L2 data cache access. This event counts any transaction from L1 which looks up in the L2 cache, and any write-back from the L1 to the L2. Snoops from outside the core and cache maintenance operations are not counted.", + "EventCode": "0x16", + "EventName": "L2D_CACHE", + "BriefDescription": "L2 data cache access" + }, + { + "PublicDescription": "L2 data cache refill. This event counts any cacheable transaction from L1 which causes data to be read from outside the core. L2 refills caused by stashes into L2 should not be counted", + "EventCode": "0x17", + "EventName": "L2D_CACHE_REFILL", + "BriefDescription": "L2 data cache refill" + }, + { + "PublicDescription": "L2 data cache write-back. This event counts any write-back of data from the L2 cache to outside the core. This includes snoops to the L2 which return data, regardless of whether they cause an invalidation. Invalidations from the L2 which do not write data outside of the core and snoops which return data from the L1 are not counted", + "EventCode": "0x18", + "EventName": "L2D_CACHE_WB", + "BriefDescription": "L2 data cache write-back" + }, + { + "PublicDescription": "L2 data cache allocation without refill. This event counts any full cache line write into the L2 cache which does not cause a linefill, including write-backs from L1 to L2 and full-line writes which do not allocate into L1.", + "EventCode": "0x20", + "EventName": "L2D_CACHE_ALLOCATE", + "BriefDescription": "L2 data cache allocation without refill" + }, + { + "PublicDescription": "Level 1 data TLB access. This event counts any load or store operation which accesses the data L1 TLB. If both a load and a store are executed on a cycle, this event counts twice. This event counts regardless of whether the MMU is enabled.", + "EventCode": "0x25", + "EventName": "L1D_TLB", + "BriefDescription": "Level 1 data TLB access." + }, + { + "PublicDescription": "Level 1 instruction TLB access. This event counts any instruction fetch which accesses the instruction L1 TLB.This event counts regardless of whether the MMU is enabled.", + "EventCode": "0x26", + "EventName": "L1I_TLB", + "BriefDescription": "Level 1 instruction TLB access" + }, + { + "PublicDescription": "This event counts any full cache line write into the L3 cache which does not cause a linefill, including write-backs from L2 to L3 and full-line writes which do not allocate into L2", + "EventCode": "0x29", + "EventName": "L3D_CACHE_ALLOCATE", + "BriefDescription": "Allocation without refill" + }, + { + "PublicDescription": "Attributable Level 3 unified cache refill. This event counts for any cacheable read transaction returning datafrom the SCU for which the data source was outside the cluster. Transactions such as ReadUnique are counted here as 'read' transactions, even though they can be generated by store instructions.", + "EventCode": "0x2A", + "EventName": "L3D_CACHE_REFILL", + "BriefDescription": "Attributable Level 3 unified cache refill." + }, + { + "PublicDescription": "Attributable Level 3 unified cache access. This event counts for any cacheable read transaction returning datafrom the SCU, or for any cacheable write to the SCU.", + "EventCode": "0x2B", + "EventName": "L3D_CACHE", + "BriefDescription": "Attributable Level 3 unified cache access." + }, + { + "PublicDescription": "Attributable L2 data or unified TLB refill. This event counts on anyrefill of the L2 TLB, caused by either an instruction or data access.This event does not count if the MMU is disabled.", + "EventCode": "0x2D", + "EventName": "L2D_TLB_REFILL", + "BriefDescription": "Attributable L2 data or unified TLB refill" + }, + { + "PublicDescription": "Attributable L2 data or unified TLB access. This event counts on any access to the L2 TLB (caused by a refill of any of the L1 TLBs). This event does not count if the MMU is disabled.", + "EventCode": "0x2F", + "EventName": "L2D_TLB", + "BriefDescription": "Attributable L2 data or unified TLB access" + }, + { + "PublicDescription": "Access to data TLB that caused a page table walk. This event counts on any data access which causes L2D_TLB_REFILL to count.", + "EventCode": "0x34", + "EventName": "DTLB_WALK", + "BriefDescription": "Access to data TLB that caused a page table walk." + }, + { + "PublicDescription": "Access to instruction TLB that caused a page table walk. This event counts on any instruction access which causes L2D_TLB_REFILL to count.", + "EventCode": "0x35", + "EventName": "ITLB_WALK", + "BriefDescription": "Access to instruction TLB that caused a page table walk." + }, + { + "EventCode": "0x36", + "EventName": "LL_CACHE_RD", + "BriefDescription": "Last level cache access, read" + }, + { + "EventCode": "0x37", + "EventName": "LL_CACHE_MISS_RD", + "BriefDescription": "Last level cache miss, read" + }, + { + "ArchStdEvent": "L1D_CACHE_INVAL" + }, + { + "ArchStdEvent": "L1D_CACHE_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_INNER" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_OUTER" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L1D_CACHE_WB_CLEAN" + }, + { + "ArchStdEvent": "L1D_CACHE_WB_VICTIM" + }, + { + "ArchStdEvent": "L1D_CACHE_WR" + }, + { + "ArchStdEvent": "L1D_TLB_RD" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L1D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L1D_TLB_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_INVAL" + }, + { + "ArchStdEvent": "L2D_CACHE_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_CACHE_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_CLEAN" + }, + { + "ArchStdEvent": "L2D_CACHE_WB_VICTIM" + }, + { + "ArchStdEvent": "L2D_CACHE_WR" + }, + { + "ArchStdEvent": "L2D_TLB_RD" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_RD" + }, + { + "ArchStdEvent": "L2D_TLB_REFILL_WR" + }, + { + "ArchStdEvent": "L2D_TLB_WR" + }, + { + "ArchStdEvent": "L3D_CACHE_RD" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/exception.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/exception.json new file mode 100644 index 000000000000..98d29c862320 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/exception.json @@ -0,0 +1,52 @@ +[ + { + "EventCode": "0x09", + "EventName": "EXC_TAKEN", + "BriefDescription": "Exception taken." + }, + { + "PublicDescription": "Local memory error. This event counts any correctable or uncorrectable memory error (ECC or parity) in the protected core RAMs", + "EventCode": "0x1A", + "EventName": "MEMORY_ERROR", + "BriefDescription": "Local memory error." + }, + { + "ArchStdEvent": "EXC_DABORT" + }, + { + "ArchStdEvent": "EXC_FIQ" + }, + { + "ArchStdEvent": "EXC_HVC" + }, + { + "ArchStdEvent": "EXC_IRQ" + }, + { + "ArchStdEvent": "EXC_PABORT" + }, + { + "ArchStdEvent": "EXC_SMC" + }, + { + "ArchStdEvent": "EXC_SVC" + }, + { + "ArchStdEvent": "EXC_TRAP_DABORT" + }, + { + "ArchStdEvent": "EXC_TRAP_FIQ" + }, + { + "ArchStdEvent": "EXC_TRAP_IRQ" + }, + { + "ArchStdEvent": "EXC_TRAP_OTHER" + }, + { + "ArchStdEvent": "EXC_TRAP_PABORT" + }, + { + "ArchStdEvent": "EXC_UNDEF" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/instruction.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/instruction.json new file mode 100644 index 000000000000..c153ac706d8d --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/instruction.json @@ -0,0 +1,108 @@ +[ + { + "PublicDescription": "Software increment. Instruction architecturally executed (condition code check pass).", + "EventCode": "0x00", + "EventName": "SW_INCR", + "BriefDescription": "Software increment." + }, + { + "PublicDescription": "Instruction architecturally executed. This event counts all retired instructions, including those that fail their condition check.", + "EventCode": "0x08", + "EventName": "INST_RETIRED", + "BriefDescription": "Instruction architecturally executed." + }, + { + "EventCode": "0x0A", + "EventName": "EXC_RETURN", + "BriefDescription": "Instruction architecturally executed, condition code check pass, exception return." + }, + { + "PublicDescription": "Instruction architecturally executed, condition code check pass, write to CONTEXTIDR. This event only counts writes to CONTEXTIDR in AArch32 state, and via the CONTEXTIDR_EL1 mnemonic in AArch64 state.", + "EventCode": "0x0B", + "EventName": "CID_WRITE_RETIRED", + "BriefDescription": "Instruction architecturally executed, condition code check pass, write to CONTEXTIDR." + }, + { + "EventCode": "0x1B", + "EventName": "INST_SPEC", + "BriefDescription": "Operation speculatively executed" + }, + { + "PublicDescription": "Instruction architecturally executed, condition code check pass, write to TTBR. This event only counts writes to TTBR0/TTBR1 in AArch32 state and TTBR0_EL1/TTBR1_EL1 in AArch64 state.", + "EventCode": "0x1C", + "EventName": "TTBR_WRITE_RETIRED", + "BriefDescription": "Instruction architecturally executed, condition code check pass, write to TTBR" + }, + { + "PublicDescription": "Instruction architecturally executed, branch. This event counts all branches, taken or not. This excludes exception entries, debug entries and CCFAIL branches.", + "EventCode": "0x21", + "EventName": "BR_RETIRED", + "BriefDescription": "Instruction architecturally executed, branch." + }, + { + "PublicDescription": "Instruction architecturally executed, mispredicted branch. This event counts any branch counted by BR_RETIRED which is not correctly predicted and causes a pipeline flush.", + "EventCode": "0x22", + "EventName": "BR_MIS_PRED_RETIRED", + "BriefDescription": "Instruction architecturally executed, mispredicted branch." + }, + { + "ArchStdEvent": "ASE_SPEC" + }, + { + "ArchStdEvent": "BR_IMMED_SPEC" + }, + { + "ArchStdEvent": "BR_INDIRECT_SPEC" + }, + { + "ArchStdEvent": "BR_RETURN_SPEC" + }, + { + "ArchStdEvent": "CRYPTO_SPEC" + }, + { + "ArchStdEvent": "DMB_SPEC" + }, + { + "ArchStdEvent": "DP_SPEC" + }, + { + "ArchStdEvent": "DSB_SPEC" + }, + { + "ArchStdEvent": "ISB_SPEC" + }, + { + "ArchStdEvent": "LDREX_SPEC" + }, + { + "ArchStdEvent": "LDST_SPEC" + }, + { + "ArchStdEvent": "LD_SPEC" + }, + { + "ArchStdEvent": "PC_WRITE_SPEC" + }, + { + "ArchStdEvent": "RC_LD_SPEC" + }, + { + "ArchStdEvent": "RC_ST_SPEC" + }, + { + "ArchStdEvent": "STREX_FAIL_SPEC" + }, + { + "ArchStdEvent": "STREX_PASS_SPEC" + }, + { + "ArchStdEvent": "STREX_SPEC" + }, + { + "ArchStdEvent": "ST_SPEC" + }, + { + "ArchStdEvent": "VFP_SPEC" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/memory.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/memory.json new file mode 100644 index 000000000000..b86643253f19 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/memory.json @@ -0,0 +1,23 @@ +[ + { + "PublicDescription": "Data memory access. This event counts memory accesses due to load or store instructions. This event counts the sum of MEM_ACCESS_RD and MEM_ACCESS_WR.", + "EventCode": "0x13", + "EventName": "MEM_ACCESS", + "BriefDescription": "Data memory access" + }, + { + "ArchStdEvent": "MEM_ACCESS_RD" + }, + { + "ArchStdEvent": "MEM_ACCESS_WR" + }, + { + "ArchStdEvent": "UNALIGNED_LD_SPEC" + }, + { + "ArchStdEvent": "UNALIGNED_ST_SPEC" + }, + { + "ArchStdEvent": "UNALIGNED_LDST_SPEC" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/other.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/other.json new file mode 100644 index 000000000000..8bde029a62d5 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/other.json @@ -0,0 +1,7 @@ +[ + { + "EventCode": "0x31", + "EventName": "REMOTE_ACCESS", + "BriefDescription": "Access to another socket in a multi-socket system" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/pipeline.json b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/pipeline.json new file mode 100644 index 000000000000..010a647f9d02 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/arm/cortex-a76-n1/pipeline.json @@ -0,0 +1,14 @@ +[ + { + "PublicDescription": "No operation issued because of the frontend. The counter counts on any cycle when there are no fetched instructions available to dispatch.", + "EventCode": "0x23", + "EventName": "STALL_FRONTEND", + "BriefDescription": "No operation issued because of the frontend." + }, + { + "PublicDescription": "No operation issued because of the backend. The counter counts on any cycle fetched instructions are not dispatched due to resource constraints.", + "EventCode": "0x24", + "EventName": "STALL_BACKEND", + "BriefDescription": "No operation issued because of the backend." + } +] diff --git a/tools/perf/pmu-events/arch/arm64/mapfile.csv b/tools/perf/pmu-events/arch/arm64/mapfile.csv index 927fcddcb4aa..0d609149b82a 100644 --- a/tools/perf/pmu-events/arch/arm64/mapfile.csv +++ b/tools/perf/pmu-events/arch/arm64/mapfile.csv @@ -16,6 +16,8 @@ 0x00000000420f1000,v1,arm/cortex-a53,core 0x00000000410fd070,v1,arm/cortex-a57-a72,core 0x00000000410fd080,v1,arm/cortex-a57-a72,core +0x00000000410fd0b0,v1,arm/cortex-a76-n1,core +0x00000000410fd0c0,v1,arm/cortex-a76-n1,core 0x00000000420f5160,v1,cavium/thunderx2,core 0x00000000430f0af0,v1,cavium/thunderx2,core 0x00000000480fd010,v1,hisilicon/hip08,core diff --git a/tools/perf/pmu-events/arch/powerpc/power8/other.json b/tools/perf/pmu-events/arch/powerpc/power8/other.json index 9dc2f6b70354..b2a3df07fbc4 100644 --- a/tools/perf/pmu-events/arch/powerpc/power8/other.json +++ b/tools/perf/pmu-events/arch/powerpc/power8/other.json @@ -1776,30 +1776,6 @@ "PublicDescription": "" }, {, - "EventCode": "0xa29084", - "EventName": "PM_L3_P0_GRP_PUMP", - "BriefDescription": "L3 pf sent with grp scope port 0", - "PublicDescription": "" - }, - {, - "EventCode": "0x528084", - "EventName": "PM_L3_P0_LCO_DATA", - "BriefDescription": "lco sent with data port 0", - "PublicDescription": "" - }, - {, - "EventCode": "0x518080", - "EventName": "PM_L3_P0_LCO_NO_DATA", - "BriefDescription": "dataless l3 lco sent port 0", - "PublicDescription": "" - }, - {, - "EventCode": "0xa4908c", - "EventName": "PM_L3_P0_LCO_RTY", - "BriefDescription": "L3 LCO received retry port 0", - "PublicDescription": "" - }, - {, "EventCode": "0x84908d", "EventName": "PM_L3_PF0_ALLOC", "BriefDescription": "lifetime, sample of PF machine 0 valid", diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/cache.json b/tools/perf/pmu-events/arch/x86/amdfam17h/cache.json index fad4af9142cb..6221a840fcea 100644 --- a/tools/perf/pmu-events/arch/x86/amdfam17h/cache.json +++ b/tools/perf/pmu-events/arch/x86/amdfam17h/cache.json @@ -283,5 +283,47 @@ "BriefDescription": "Total cycles spent with one or more fill requests in flight from L2.", "PublicDescription": "Total cycles spent with one or more fill requests in flight from L2.", "UMask": "0x1" + }, + { + "EventName": "l3_request_g1.caching_l3_cache_accesses", + "EventCode": "0x01", + "BriefDescription": "Caching: L3 cache accesses", + "UMask": "0x80", + "Unit": "L3PMC" + }, + { + "EventName": "l3_lookup_state.all_l3_req_typs", + "EventCode": "0x04", + "BriefDescription": "All L3 Request Types", + "UMask": "0xff", + "Unit": "L3PMC" + }, + { + "EventName": "l3_comb_clstr_state.other_l3_miss_typs", + "EventCode": "0x06", + "BriefDescription": "Other L3 Miss Request Types", + "UMask": "0xfe", + "Unit": "L3PMC" + }, + { + "EventName": "l3_comb_clstr_state.request_miss", + "EventCode": "0x06", + "BriefDescription": "L3 cache misses", + "UMask": "0x01", + "Unit": "L3PMC" + }, + { + "EventName": "xi_sys_fill_latency", + "EventCode": "0x90", + "BriefDescription": "L3 Cache Miss Latency. Total cycles for all transactions divided by 16. Ignores SliceMask and ThreadMask.", + "UMask": "0x00", + "Unit": "L3PMC" + }, + { + "EventName": "xi_ccx_sdp_req1.all_l3_miss_req_typs", + "EventCode": "0x9a", + "BriefDescription": "All L3 Miss Request Types. Ignores SliceMask and ThreadMask.", + "UMask": "0x3f", + "Unit": "L3PMC" } ] diff --git a/tools/perf/pmu-events/arch/x86/amdfam17h/core.json b/tools/perf/pmu-events/arch/x86/amdfam17h/core.json index 7b285b0a7f35..1079544eeed5 100644 --- a/tools/perf/pmu-events/arch/x86/amdfam17h/core.json +++ b/tools/perf/pmu-events/arch/x86/amdfam17h/core.json @@ -13,7 +13,7 @@ { "EventName": "ex_ret_brn", "EventCode": "0xc2", - "BriefDescription": "[Retired Branch Instructions.", + "BriefDescription": "Retired Branch Instructions.", "PublicDescription": "The number of branch instructions retired. This includes all types of architectural control flow changes, including exceptions and interrupts." }, { diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index d413761621b0..9e37287da924 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -239,6 +239,7 @@ static struct map { { "hisi_sccl,ddrc", "hisi_sccl,ddrc" }, { "hisi_sccl,hha", "hisi_sccl,hha" }, { "hisi_sccl,l3c", "hisi_sccl,l3c" }, + { "L3PMC", "amd_l3" }, {} }; diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c index a637a4a90760..338cd9faa835 100644 --- a/tools/perf/tests/backward-ring-buffer.c +++ b/tools/perf/tests/backward-ring-buffer.c @@ -10,6 +10,7 @@ #include "tests.h" #include "debug.h" #include "parse-events.h" +#include "util/mmap.h" #include <errno.h> #include <linux/string.h> @@ -32,8 +33,8 @@ static int count_samples(struct evlist *evlist, int *sample_count, { int i; - for (i = 0; i < evlist->nr_mmaps; i++) { - struct perf_mmap *map = &evlist->overwrite_mmap[i]; + for (i = 0; i < evlist->core.nr_mmaps; i++) { + struct mmap *map = &evlist->overwrite_mmap[i]; union perf_event *event; perf_mmap__read_init(map); @@ -63,9 +64,9 @@ static int do_test(struct evlist *evlist, int mmap_pages, int err; char sbuf[STRERR_BUFSIZE]; - err = perf_evlist__mmap(evlist, mmap_pages); + err = evlist__mmap(evlist, mmap_pages); if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", + pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); return TEST_FAIL; } @@ -75,7 +76,7 @@ static int do_test(struct evlist *evlist, int mmap_pages, evlist__disable(evlist); err = count_samples(evlist, sample_count, comm_count); - perf_evlist__munmap(evlist); + evlist__munmap(evlist); return err; } diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c index db2aadff3708..96c137360918 100644 --- a/tools/perf/tests/bitmap.c +++ b/tools/perf/tests/bitmap.c @@ -2,8 +2,8 @@ #include <linux/compiler.h> #include <linux/bitmap.h> #include <perf/cpumap.h> +#include <internal/cpumap.h> #include "tests.h" -#include "cpumap.h" #include "debug.h" #define NBITS 100 diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index fc102e4f403e..1eb0bffaed6c 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c @@ -19,6 +19,7 @@ #include "llvm.h" #include "debug.h" #include "parse-events.h" +#include "util/mmap.h" #define NR_ITERS 111 #define PERF_TEST_BPF_PATH "/sys/fs/bpf/perf_test" @@ -167,9 +168,9 @@ static int do_test(struct bpf_object *obj, int (*func)(void), goto out_delete_evlist; } - err = perf_evlist__mmap(evlist, opts.mmap_pages); + err = evlist__mmap(evlist, opts.mmap_pages); if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", + pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -178,9 +179,9 @@ static int do_test(struct bpf_object *obj, int (*func)(void), (*func)(); evlist__disable(evlist); - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { union perf_event *event; - struct perf_mmap *md; + struct mmap *md; md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c index f45fe11dcf50..2577d3ed1531 100644 --- a/tools/perf/tests/clang.c +++ b/tools/perf/tests/clang.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "tests.h" -#include "debug.h" -#include "util.h" #include "c++/clang-c.h" #include <linux/kernel.h> diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index c1c29e08e7fb..f5764a3890b9 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -19,12 +19,13 @@ #include "evlist.h" #include "evsel.h" #include "thread_map.h" -#include "cpumap.h" #include "machine.h" #include "map.h" #include "symbol.h" #include "event.h" #include "record.h" +#include "util/mmap.h" +#include "util/synthetic-events.h" #include "thread.h" #include "tests.h" @@ -419,10 +420,10 @@ static int process_events(struct machine *machine, struct evlist *evlist, struct state *state) { union perf_event *event; - struct perf_mmap *md; + struct mmap *md; int i, ret; - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) continue; @@ -651,7 +652,7 @@ static int do_test_code_reading(bool try_kcore) perf_evlist__config(evlist, &opts, NULL); - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); evsel->core.attr.comm = 1; evsel->core.attr.disabled = 1; @@ -685,9 +686,9 @@ static int do_test_code_reading(bool try_kcore) break; } - ret = perf_evlist__mmap(evlist, UINT_MAX); + ret = evlist__mmap(evlist, UINT_MAX); if (ret < 0) { - pr_debug("perf_evlist__mmap failed\n"); + pr_debug("evlist__mmap failed\n"); goto out_put; } diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 39493de50117..8a0d236202b0 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -3,6 +3,7 @@ #include <stdio.h> #include "cpumap.h" #include "event.h" +#include "util/synthetic-events.h" #include <string.h> #include <linux/bitops.h> #include <perf/cpumap.h> diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index a4874d4ce7ef..627c1aaf1c9e 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -10,7 +10,6 @@ #include <sys/resource.h> #include <api/fs/fs.h> #include "dso.h" -#include "util.h" #include "machine.h" #include "symbol.h" #include "tests.h" diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index 4125255ff637..4f4ecbcbe87e 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -15,6 +15,7 @@ #include "symbol.h" #include "thread.h" #include "callchain.h" +#include "util/synthetic-events.h" #if defined (__x86_64__) || defined (__i386__) || defined (__powerpc__) #include "arch-tests.h" diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index d824a726906c..1ee8704e2284 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -9,7 +9,6 @@ #include "tests.h" #include "evlist.h" #include "evsel.h" -#include "util.h" #include "debug.h" #include "parse-events.h" #include "thread_map.h" @@ -17,7 +16,7 @@ static int attach__enable_on_exec(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = evlist__last(evlist); struct target target = { .uid = UINT_MAX, }; @@ -59,7 +58,7 @@ static int detach__enable_on_exec(struct evlist *evlist) static int attach__current_disabled(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = evlist__last(evlist); struct perf_thread_map *threads; int err; @@ -85,7 +84,7 @@ static int attach__current_disabled(struct evlist *evlist) static int attach__current_enabled(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = evlist__last(evlist); struct perf_thread_map *threads; int err; @@ -105,14 +104,14 @@ static int attach__current_enabled(struct evlist *evlist) static int detach__disable(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = evlist__last(evlist); return evsel__enable(evsel); } static int attach__cpu_disabled(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = evlist__last(evlist); struct perf_cpu_map *cpus; int err; @@ -141,7 +140,7 @@ static int attach__cpu_disabled(struct evlist *evlist) static int attach__cpu_enabled(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__last(evlist); + struct evsel *evsel = evlist__last(evlist); struct perf_cpu_map *cpus; int err; @@ -181,7 +180,7 @@ static int test_times(int (attach)(struct evlist *), goto out_err; } - evsel = perf_evlist__last(evlist); + evsel = evlist__last(evlist); evsel->core.attr.read_format |= PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index cac4290e233a..c727379cf20e 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c @@ -2,10 +2,12 @@ #include <linux/compiler.h> #include <perf/cpumap.h> #include <string.h> +#include "cpumap.h" #include "evlist.h" #include "evsel.h" #include "header.h" #include "machine.h" +#include "util/synthetic-events.h" #include "tool.h" #include "tests.h" #include "debug.h" @@ -90,12 +92,12 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu evlist = perf_evlist__new_default(); TEST_ASSERT_VAL("failed to get evlist", evlist); - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); - TEST_ASSERT_VAL("failed to allos ids", - !perf_evsel__alloc_id(evsel, 1, 1)); + TEST_ASSERT_VAL("failed to allocate ids", + !perf_evsel__alloc_id(&evsel->core, 1, 1)); - perf_evlist__id_add(evlist, evsel, 0, 0, 123); + perf_evlist__id_add(&evlist->core, &evsel->core, 0, 0, 123); evsel->unit = strdup("KRAVA"); diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 5330f106a6ee..956205bf9326 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c @@ -34,7 +34,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) } idx = 0; - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c index de110d8f169b..6f34d08b84e5 100644 --- a/tools/perf/tests/hists_common.c +++ b/tools/perf/tests/hists_common.c @@ -2,6 +2,7 @@ #include <inttypes.h> #include "util/debug.h" #include "util/dso.h" +#include "util/event.h" // struct perf_sample #include "util/map.h" #include "util/symbol.h" #include "util/sort.h" @@ -10,6 +11,7 @@ #include "util/thread.h" #include "tests/hists_common.h" #include <linux/kernel.h> +#include <linux/perf_event.h> static struct { u32 pid; diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index fa55b7bad3af..6367c8f6ca22 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -721,7 +721,7 @@ int test__hists_cumulate(struct test *test __maybe_unused, int subtest __maybe_u if (verbose > 1) machine__fprintf(machine, stderr); - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); for (i = 0; i < ARRAY_SIZE(testcases); i++) { err = testcases[i](evsel, machine); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 8be4d0b61e3a..a024d3f3a412 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -8,6 +8,7 @@ #include "machine.h" #include "parse-events.h" #include "hists_common.h" +#include "util/mmap.h" #include <errno.h> #include <linux/kernel.h> @@ -310,8 +311,8 @@ int test__hists_link(struct test *test __maybe_unused, int subtest __maybe_unuse print_hists_in(hists); } - first = perf_evlist__first(evlist); - evsel = perf_evlist__last(evlist); + first = evlist__first(evlist); + evsel = evlist__last(evlist); first_hists = evsel__hists(first); hists = evsel__hists(evsel); diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index 3f6dfa212260..38f804ff6452 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -608,7 +608,7 @@ int test__hists_output(struct test *test __maybe_unused, int subtest __maybe_unu if (verbose > 1) machine__fprintf(machine, stderr); - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); for (i = 0; i < ARRAY_SIZE(testcases); i++) { err = testcases[i](evsel, machine); diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 9f0762d987fa..92c7d591bcac 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -12,8 +12,8 @@ #include "evsel.h" #include "record.h" #include "thread_map.h" -#include "cpumap.h" #include "tests.h" +#include "util/mmap.h" #define CHECK__(x) { \ while ((x) < 0) { \ @@ -32,11 +32,11 @@ static int find_comm(struct evlist *evlist, const char *comm) { union perf_event *event; - struct perf_mmap *md; + struct mmap *md; int i, found; found = 0; - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) continue; @@ -93,7 +93,7 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un perf_evlist__config(evlist, &opts, NULL); - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); evsel->core.attr.comm = 1; evsel->core.attr.disabled = 1; @@ -105,7 +105,7 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un goto out_err; } - CHECK__(perf_evlist__mmap(evlist, UINT_MAX)); + CHECK__(evlist__mmap(evlist, UINT_MAX)); /* * First, test that a 'comm' event can be found when the event is @@ -132,7 +132,7 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un evlist__enable(evlist); - evsel = perf_evlist__last(evlist); + evsel = evlist__last(evlist); CHECK__(evsel__disable(evsel)); @@ -143,7 +143,7 @@ int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_un found = find_comm(evlist, comm); if (found != 1) { - pr_debug("Seconf time, failed to find tracking event.\n"); + pr_debug("Second time, failed to find tracking event.\n"); goto out_err; } diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index 022e4c9cf092..ae6cda81c209 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c @@ -7,7 +7,6 @@ #include "llvm.h" #include "tests.h" #include "debug.h" -#include "util.h" #ifdef HAVE_LIBBPF_SUPPORT static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 70c48475896d..c850d1664c56 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -100,7 +100,7 @@ make_install_info := install-info make_install_pdf := install-pdf make_install_prefix := install prefix=/tmp/krava make_install_prefix_slash := install prefix=/tmp/krava/ -make_static := LDFLAGS=-static +make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1 # all the NO_* variable combined make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 @@ -327,6 +327,10 @@ make_kernelsrc_tools: (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \ test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false) +make_libperf: + @echo "- make -C lib"; + make -C lib clean >$@ 2>&1; make -C lib >>$@ 2>&1 && rm $@ + FEATURES_DUMP_FILE := $(FULL_O)/BUILD_TEST_FEATURE_DUMP FEATURES_DUMP_FILE_STATIC := $(FULL_O)/BUILD_TEST_FEATURE_DUMP_STATIC @@ -365,5 +369,5 @@ $(foreach t,$(run),$(if $(findstring make_static,$(t)),\ $(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE)))) endif -.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools +.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools make_libperf endif # ifndef MK diff --git a/tools/perf/tests/mem2node.c b/tools/perf/tests/mem2node.c index 7672ade70f20..a258bd51f1a4 100644 --- a/tools/perf/tests/mem2node.c +++ b/tools/perf/tests/mem2node.c @@ -4,7 +4,7 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <perf/cpumap.h> -#include "cpumap.h" +#include <internal/cpumap.h> #include "debug.h" #include "env.h" #include "mem2node.h" diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 85e1d7337dc0..3a22dce991ba 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -10,8 +10,8 @@ #include "evlist.h" #include "evsel.h" #include "thread_map.h" -#include "cpumap.h" #include "tests.h" +#include "util/mmap.h" #include <linux/err.h> #include <linux/kernel.h> #include <linux/string.h> @@ -43,7 +43,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse expected_nr_events[nsyscalls], i, j; struct evsel *evsels[nsyscalls], *evsel; char sbuf[STRERR_BUFSIZE]; - struct perf_mmap *md; + struct mmap *md; threads = thread_map__new(-1, getpid(), UINT_MAX); if (threads == NULL) { @@ -53,7 +53,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse cpus = perf_cpu_map__new(NULL); if (cpus == NULL) { - pr_debug("cpu_map__new\n"); + pr_debug("perf_cpu_map__new\n"); goto out_free_threads; } @@ -100,7 +100,7 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse expected_nr_events[i] = 1 + rand() % 127; } - if (perf_evlist__mmap(evlist, 128) < 0) { + if (evlist__mmap(evlist, 128) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index 360d70deb855..8d9d4cbff76d 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -8,13 +8,15 @@ #include <stdlib.h> #include <stdio.h> #include "debug.h" +#include "event.h" #include "tests.h" #include "machine.h" #include "thread_map.h" #include "map.h" #include "symbol.h" +#include "util/synthetic-events.h" #include "thread.h" -#include "util.h" +#include <internal/lib.h> // page_size #define THREADS 4 diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 9171f77cd9cd..93c176523e38 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -14,7 +14,8 @@ #include "evsel.h" #include "tests.h" #include "thread_map.h" -#include "cpumap.h" +#include <perf/cpumap.h> +#include <internal/cpumap.h> #include "debug.h" #include "stat.h" #include "util/counts.h" @@ -37,7 +38,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int cpus = perf_cpu_map__new(NULL); if (cpus == NULL) { - pr_debug("cpu_map__new\n"); + pr_debug("perf_cpu_map__new\n"); goto out_thread_map_delete; } diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index b71167b43dda..2b5c46813053 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -11,6 +11,7 @@ #include "record.h" #include "tests.h" #include "debug.h" +#include "util/mmap.h" #include <errno.h> #ifndef O_DIRECTORY @@ -69,9 +70,9 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest goto out_delete_evlist; } - err = perf_evlist__mmap(evlist, UINT_MAX); + err = evlist__mmap(evlist, UINT_MAX); if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", + pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -86,9 +87,9 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest while (1) { int before = nr_events; - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { union perf_event *event; - struct perf_mmap *md; + struct mmap *md; md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) @@ -126,7 +127,7 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest } if (nr_events == before) - perf_evlist__poll(evlist, 10); + evlist__poll(evlist, 10); if (++nr_polls > 5) { pr_debug("%s: no events!\n", __func__); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 02ba696fb87f..25e0ed2eedfc 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -6,7 +6,6 @@ #include "tests.h" #include "debug.h" #include "pmu.h" -#include "util.h" #include <dirent.h> #include <errno.h> #include <sys/types.h> @@ -47,7 +46,7 @@ static bool kvm_s390_create_vm_valid(void) static int test__checkevent_tracepoint(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); @@ -78,7 +77,7 @@ static int test__checkevent_tracepoint_multi(struct evlist *evlist) static int test__checkevent_raw(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); @@ -88,7 +87,7 @@ static int test__checkevent_raw(struct evlist *evlist) static int test__checkevent_numeric(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", 1 == evsel->core.attr.type); @@ -98,7 +97,7 @@ static int test__checkevent_numeric(struct evlist *evlist) static int test__checkevent_symbolic_name(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); @@ -109,7 +108,7 @@ static int test__checkevent_symbolic_name(struct evlist *evlist) static int test__checkevent_symbolic_name_config(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); @@ -130,7 +129,7 @@ static int test__checkevent_symbolic_name_config(struct evlist *evlist) static int test__checkevent_symbolic_alias(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); @@ -141,7 +140,7 @@ static int test__checkevent_symbolic_alias(struct evlist *evlist) static int test__checkevent_genhw(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); @@ -151,7 +150,7 @@ static int test__checkevent_genhw(struct evlist *evlist) static int test__checkevent_breakpoint(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); @@ -165,7 +164,7 @@ static int test__checkevent_breakpoint(struct evlist *evlist) static int test__checkevent_breakpoint_x(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); @@ -178,7 +177,7 @@ static int test__checkevent_breakpoint_x(struct evlist *evlist) static int test__checkevent_breakpoint_r(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", @@ -193,7 +192,7 @@ static int test__checkevent_breakpoint_r(struct evlist *evlist) static int test__checkevent_breakpoint_w(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", @@ -208,7 +207,7 @@ static int test__checkevent_breakpoint_w(struct evlist *evlist) static int test__checkevent_breakpoint_rw(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", @@ -223,7 +222,7 @@ static int test__checkevent_breakpoint_rw(struct evlist *evlist) static int test__checkevent_tracepoint_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); @@ -254,7 +253,7 @@ test__checkevent_tracepoint_multi_modifier(struct evlist *evlist) static int test__checkevent_raw_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); @@ -266,7 +265,7 @@ static int test__checkevent_raw_modifier(struct evlist *evlist) static int test__checkevent_numeric_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -278,7 +277,7 @@ static int test__checkevent_numeric_modifier(struct evlist *evlist) static int test__checkevent_symbolic_name_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -290,7 +289,7 @@ static int test__checkevent_symbolic_name_modifier(struct evlist *evlist) static int test__checkevent_exclude_host_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", evsel->core.attr.exclude_host); @@ -300,7 +299,7 @@ static int test__checkevent_exclude_host_modifier(struct evlist *evlist) static int test__checkevent_exclude_guest_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); @@ -310,7 +309,7 @@ static int test__checkevent_exclude_guest_modifier(struct evlist *evlist) static int test__checkevent_symbolic_alias_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -322,7 +321,7 @@ static int test__checkevent_symbolic_alias_modifier(struct evlist *evlist) static int test__checkevent_genhw_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); @@ -334,7 +333,7 @@ static int test__checkevent_genhw_modifier(struct evlist *evlist) static int test__checkevent_exclude_idle_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude idle", evsel->core.attr.exclude_idle); TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); @@ -349,7 +348,7 @@ static int test__checkevent_exclude_idle_modifier(struct evlist *evlist) static int test__checkevent_exclude_idle_modifier_1(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude idle", evsel->core.attr.exclude_idle); TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); @@ -364,7 +363,7 @@ static int test__checkevent_exclude_idle_modifier_1(struct evlist *evlist) static int test__checkevent_breakpoint_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); @@ -379,7 +378,7 @@ static int test__checkevent_breakpoint_modifier(struct evlist *evlist) static int test__checkevent_breakpoint_x_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); @@ -393,7 +392,7 @@ static int test__checkevent_breakpoint_x_modifier(struct evlist *evlist) static int test__checkevent_breakpoint_r_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -407,7 +406,7 @@ static int test__checkevent_breakpoint_r_modifier(struct evlist *evlist) static int test__checkevent_breakpoint_w_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -421,7 +420,7 @@ static int test__checkevent_breakpoint_w_modifier(struct evlist *evlist) static int test__checkevent_breakpoint_rw_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); @@ -436,7 +435,7 @@ static int test__checkevent_breakpoint_rw_modifier(struct evlist *evlist) static int test__checkevent_pmu(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); @@ -454,7 +453,7 @@ static int test__checkevent_pmu(struct evlist *evlist) static int test__checkevent_list(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); @@ -493,7 +492,7 @@ static int test__checkevent_list(struct evlist *evlist) static int test__checkevent_pmu_name(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); /* cpu/config=1,name=krava/u */ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); @@ -514,7 +513,7 @@ static int test__checkevent_pmu_name(struct evlist *evlist) static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); /* cpu/config=1,call-graph=fp,time,period=100000/ */ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); @@ -547,7 +546,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct evlist *evlist) static int test__checkevent_pmu_events(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); @@ -565,7 +564,7 @@ static int test__checkevent_pmu_events(struct evlist *evlist) static int test__checkevent_pmu_events_mix(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); /* pmu-event:u */ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); @@ -643,7 +642,7 @@ static int test__group1(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* instructions:k */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); @@ -685,7 +684,7 @@ static int test__group2(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* faults + :ku modifier */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_SW_PAGE_FAULTS == evsel->core.attr.config); @@ -740,7 +739,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); /* group1 syscalls:sys_enter_openat:H */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->core.attr.type); TEST_ASSERT_VAL("wrong sample_type", PERF_TP_SAMPLE_TYPE == evsel->core.attr.sample_type); @@ -832,7 +831,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles:u + p */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -876,7 +875,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups); /* cycles + G */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -962,7 +961,7 @@ static int test__group_gh1(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles + :H group modifier */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -1002,7 +1001,7 @@ static int test__group_gh2(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles + :G group modifier */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -1042,7 +1041,7 @@ static int test__group_gh3(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles:G + :u group modifier */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -1082,7 +1081,7 @@ static int test__group_gh4(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); /* cycles:G + :uG group modifier */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -1121,7 +1120,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); /* cycles - sampling group leader */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -1174,7 +1173,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); /* instructions - sampling group leader */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_INSTRUCTIONS == evsel->core.attr.config); @@ -1208,7 +1207,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) static int test__checkevent_pinned_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -1226,7 +1225,7 @@ static int test__pinned_group(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->core.nr_entries); /* cycles - group leader */ - evsel = leader = perf_evlist__first(evlist); + evsel = leader = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); TEST_ASSERT_VAL("wrong config", PERF_COUNT_HW_CPU_CYCLES == evsel->core.attr.config); @@ -1252,7 +1251,7 @@ static int test__pinned_group(struct evlist *evlist) static int test__checkevent_breakpoint_len(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); @@ -1267,7 +1266,7 @@ static int test__checkevent_breakpoint_len(struct evlist *evlist) static int test__checkevent_breakpoint_len_w(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->core.attr.type); @@ -1283,7 +1282,7 @@ static int test__checkevent_breakpoint_len_w(struct evlist *evlist) static int test__checkevent_breakpoint_len_rw_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); @@ -1295,7 +1294,7 @@ test__checkevent_breakpoint_len_rw_modifier(struct evlist *evlist) static int test__checkevent_precise_max_modifier(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); @@ -1306,7 +1305,7 @@ static int test__checkevent_precise_max_modifier(struct evlist *evlist) static int test__checkevent_config_symbol(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "insn") == 0); return 0; @@ -1314,7 +1313,7 @@ static int test__checkevent_config_symbol(struct evlist *evlist) static int test__checkevent_config_raw(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "rawpmu") == 0); return 0; @@ -1322,7 +1321,7 @@ static int test__checkevent_config_raw(struct evlist *evlist) static int test__checkevent_config_num(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "numpmu") == 0); return 0; @@ -1330,7 +1329,7 @@ static int test__checkevent_config_num(struct evlist *evlist) static int test__checkevent_config_cache(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "cachepmu") == 0); return 0; @@ -1343,7 +1342,7 @@ static bool test__intel_pt_valid(void) static int test__intel_pt(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "intel_pt//u") == 0); return 0; @@ -1351,7 +1350,7 @@ static int test__intel_pt(struct evlist *evlist) static int test__checkevent_complex_name(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong complex name parsing", strcmp(evsel->name, "COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks") == 0); return 0; @@ -1359,7 +1358,7 @@ static int test__checkevent_complex_name(struct evlist *evlist) static int test__sym_event_slash(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES); @@ -1369,7 +1368,7 @@ static int test__sym_event_slash(struct evlist *evlist) static int test__sym_event_dc(struct evlist *evlist) { - struct evsel *evsel = perf_evlist__first(evlist); + struct evsel *evsel = evlist__first(evlist); TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE); TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES); diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c index 8284752a60c8..adf3c9c4a416 100644 --- a/tools/perf/tests/parse-no-sample-id-all.c +++ b/tools/perf/tests/parse-no-sample-id-all.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> #include <linux/types.h> #include <stddef.h> @@ -8,7 +7,6 @@ #include "event.h" #include "evlist.h" #include "header.h" -#include "util.h" #include "debug.h" static int process_event(struct evlist **pevlist, union perf_event *event) diff --git a/tools/perf/tests/perf-hooks.c b/tools/perf/tests/perf-hooks.c index a693bcf017ea..dbc27199c65e 100644 --- a/tools/perf/tests/perf-hooks.c +++ b/tools/perf/tests/perf-hooks.c @@ -4,7 +4,6 @@ #include "tests.h" #include "debug.h" -#include "util.h" #include "perf-hooks.h" static void sigsegv_handler(int sig __maybe_unused) diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index e1b42292cf7f..437426be29e9 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -11,6 +11,7 @@ #include "debug.h" #include "record.h" #include "tests.h" +#include "util/mmap.h" static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp) { @@ -103,7 +104,7 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus /* * Config the evsels, setting attr->comm on the first one, etc. */ - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); perf_evsel__set_sample_bit(evsel, CPU); perf_evsel__set_sample_bit(evsel, TID); perf_evsel__set_sample_bit(evsel, TIME); @@ -143,9 +144,9 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus * fds in the same CPU to be injected in the same mmap ring buffer * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)). */ - err = perf_evlist__mmap(evlist, opts.mmap_pages); + err = evlist__mmap(evlist, opts.mmap_pages); if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", + pr_debug("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } @@ -164,9 +165,9 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus while (1) { int before = total_events; - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { union perf_event *event; - struct perf_mmap *md; + struct mmap *md; md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) @@ -286,7 +287,7 @@ int test__PERF_RECORD(struct test *test __maybe_unused, int subtest __maybe_unus * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. */ if (total_events == before && false) - perf_evlist__poll(evlist, -1); + evlist__poll(evlist, -1); sleep(1); if (++wakeups > 5) { diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index 14a78898d79e..74379ff1f7fa 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "parse-events.h" #include "pmu.h" -#include "util.h" #include "tests.h" #include <errno.h> #include <stdio.h> diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c index 5fcc06817076..3a02426db9a6 100644 --- a/tools/perf/tests/sample-parsing.c +++ b/tools/perf/tests/sample-parsing.c @@ -9,10 +9,10 @@ #include "map_symbol.h" #include "branch.h" -#include "util.h" #include "event.h" #include "evsel.h" #include "debug.h" +#include "util/synthetic-events.h" #include "tests.h" diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c index cf1bd57d3023..60f0e9ee04fb 100644 --- a/tools/perf/tests/sdt.c +++ b/tools/perf/tests/sdt.c @@ -3,6 +3,7 @@ #include <limits.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <sys/epoll.h> #include <util/symbol.h> #include <linux/filter.h> diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c index cc10b4116c9f..c1911501c39c 100644 --- a/tools/perf/tests/stat.c +++ b/tools/perf/tests/stat.c @@ -5,6 +5,7 @@ #include "stat.h" #include "counts.h" #include "debug.h" +#include "util/synthetic-events.h" static bool has_term(struct perf_record_stat_config *config, u64 tag, u64 val) diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 97694a040986..84519df87f30 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -12,6 +12,7 @@ #include "util/evsel.h" #include "util/evlist.h" #include "util/cpumap.h" +#include "util/mmap.h" #include "util/thread_map.h" #include <perf/evlist.h> @@ -42,7 +43,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) }; struct perf_cpu_map *cpus; struct perf_thread_map *threads; - struct perf_mmap *md; + struct mmap *md; attr.sample_freq = 500; @@ -82,7 +83,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) goto out_delete_evlist; } - err = perf_evlist__mmap(evlist, 128); + err = evlist__mmap(evlist, 128); if (err < 0) { pr_debug("failed to mmap event: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index 1a60fa1219f5..ffa592e0020e 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -14,9 +14,9 @@ #include "evlist.h" #include "evsel.h" #include "thread_map.h" -#include "cpumap.h" #include "record.h" #include "tests.h" +#include "util/mmap.h" static int spin_sleep(void) { @@ -144,7 +144,7 @@ static int process_sample_event(struct evlist *evlist, return err; /* * Check for no missing sched_switch events i.e. that the - * evsel->system_wide flag has worked. + * evsel->core.system_wide flag has worked. */ if (switch_tracking->tids[cpu] != -1 && switch_tracking->tids[cpu] != prev_tid) { @@ -264,10 +264,10 @@ static int process_events(struct evlist *evlist, unsigned pos, cnt = 0; LIST_HEAD(events); struct event_node *events_array, *node; - struct perf_mmap *md; + struct mmap *md; int i, ret; - for (i = 0; i < evlist->nr_mmaps; i++) { + for (i = 0; i < evlist->core.nr_mmaps; i++) { md = &evlist->mmap[i]; if (perf_mmap__read_init(md) < 0) continue; @@ -316,7 +316,7 @@ out_free_nodes: * * This function implements a test that checks that sched_switch events and * tracking events can be recorded for a workload (current process) using the - * evsel->system_wide and evsel->tracking flags (respectively) with other events + * evsel->core.system_wide and evsel->tracking flags (respectively) with other events * sometimes enabled or disabled. */ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_unused) @@ -367,7 +367,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - cpu_clocks_evsel = perf_evlist__last(evlist); + cpu_clocks_evsel = evlist__last(evlist); /* Second event */ err = parse_events(evlist, "cycles:u", NULL); @@ -376,7 +376,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - cycles_evsel = perf_evlist__last(evlist); + cycles_evsel = evlist__last(evlist); /* Third event */ if (!perf_evlist__can_select_event(evlist, sched_switch)) { @@ -391,22 +391,22 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - switch_evsel = perf_evlist__last(evlist); + switch_evsel = evlist__last(evlist); perf_evsel__set_sample_bit(switch_evsel, CPU); perf_evsel__set_sample_bit(switch_evsel, TIME); - switch_evsel->system_wide = true; + switch_evsel->core.system_wide = true; switch_evsel->no_aux_samples = true; switch_evsel->immediate = true; /* Test moving an event to the front */ - if (cycles_evsel == perf_evlist__first(evlist)) { + if (cycles_evsel == evlist__first(evlist)) { pr_debug("cycles event already at front"); goto out_err; } perf_evlist__to_front(evlist, cycles_evsel); - if (cycles_evsel != perf_evlist__first(evlist)) { + if (cycles_evsel != evlist__first(evlist)) { pr_debug("Failed to move cycles event to front"); goto out_err; } @@ -421,7 +421,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out_err; } - tracking_evsel = perf_evlist__last(evlist); + tracking_evsel = evlist__last(evlist); perf_evlist__set_tracking_event(evlist, tracking_evsel); @@ -434,7 +434,7 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ perf_evlist__config(evlist, &opts, NULL); /* Check moved event is still at the front */ - if (cycles_evsel != perf_evlist__first(evlist)) { + if (cycles_evsel != evlist__first(evlist)) { pr_debug("Front event no longer at front"); goto out_err; } @@ -461,9 +461,9 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_ goto out; } - err = perf_evlist__mmap(evlist, UINT_MAX); + err = evlist__mmap(evlist, UINT_MAX); if (err) { - pr_debug("perf_evlist__mmap failed!\n"); + pr_debug("evlist__mmap failed!\n"); goto out_err; } diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index f610e8c0a083..bce3a4cb4c89 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -4,12 +4,13 @@ #include "evsel.h" #include "target.h" #include "thread_map.h" -#include "cpumap.h" #include "tests.h" +#include "util/mmap.h" #include <errno.h> #include <signal.h> #include <linux/string.h> +#include <perf/cpumap.h> #include <perf/evlist.h> static int exited; @@ -51,7 +52,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused char sbuf[STRERR_BUFSIZE]; struct perf_cpu_map *cpus; struct perf_thread_map *threads; - struct perf_mmap *md; + struct mmap *md; signal(SIGCHLD, sig_handler); @@ -87,7 +88,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused goto out_delete_evlist; } - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); evsel->core.attr.task = 1; #ifdef __s390x__ evsel->core.attr.sample_freq = 1000000; @@ -106,7 +107,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused goto out_delete_evlist; } - if (perf_evlist__mmap(evlist, 128) < 0) { + if (evlist__mmap(evlist, 128) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; @@ -129,7 +130,7 @@ retry: out_init: if (!exited || !nr_exit) { - perf_evlist__poll(evlist, -1); + evlist__poll(evlist, -1); goto retry; } diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c index 39168c57943b..28f51c4bd373 100644 --- a/tools/perf/tests/thread-map.c +++ b/tools/perf/tests/thread-map.c @@ -8,6 +8,7 @@ #include "thread_map.h" #include "debug.h" #include "event.h" +#include "util/synthetic-events.h" #include <linux/zalloc.h> #include <perf/event.h> diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index a4f9f5182b47..4a800499d7c3 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -3,11 +3,12 @@ #include <stdlib.h> #include <stdio.h> #include <perf/cpumap.h> +#include "cpumap.h" #include "tests.h" -#include "util.h" #include "session.h" #include "evlist.h" #include "debug.h" +#include <linux/err.h> #define TEMPL "/tmp/perf-test-XXXXXX" #define DATA_SIZE 10 @@ -39,7 +40,7 @@ static int session_write_header(char *path) }; session = perf_session__new(&data, false, NULL); - TEST_ASSERT_VAL("can't get session", session); + TEST_ASSERT_VAL("can't get session", !IS_ERR(session)); session->evlist = perf_evlist__new_default(); TEST_ASSERT_VAL("can't get evlist", session->evlist); @@ -70,7 +71,7 @@ static int check_cpu_topology(char *path, struct perf_cpu_map *map) int i; session = perf_session__new(&data, false, NULL); - TEST_ASSERT_VAL("can't get session", session); + TEST_ASSERT_VAL("can't get session", !IS_ERR(session)); /* On platforms with large numbers of CPUs process_cpu_topology() * might issue an error while reading the perf.data file section diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 01f434c067c6..aa296ffea6d1 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -7,7 +7,7 @@ #include "dso.h" #include "map.h" #include "symbol.h" -#include "util.h" +#include <internal/lib.h> // page_size #include "tests.h" #include "debug.h" #include "machine.h" diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index f93d40b1c203..781afe42e90e 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../util/util.h" #include "../util/string2.h" #include "../util/config.h" #include "libslang.h" diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ac74ed2c23a0..82207db8f97c 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -2,7 +2,6 @@ #include "../browser.h" #include "../helpline.h" #include "../ui.h" -#include "../util.h" #include "../../util/annotate.h" #include "../../util/debug.h" #include "../../util/dso.h" diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c index 0f59a7001479..57e6e4332f74 100644 --- a/tools/perf/ui/browsers/header.c +++ b/tools/perf/ui/browsers/header.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "util/debug.h" #include "ui/browser.h" #include "ui/keysyms.h" #include "ui/ui.h" diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 589168ca9f62..7a7187e069b4 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -3319,13 +3319,13 @@ browse_hists: switch (key) { case K_TAB: if (pos->core.node.next == &evlist->core.entries) - pos = perf_evlist__first(evlist); + pos = evlist__first(evlist); else pos = perf_evsel__next(pos); goto browse_hists; case K_UNTAB: if (pos->core.node.prev == &evlist->core.entries) - pos = perf_evlist__last(evlist); + pos = evlist__last(evlist); else pos = perf_evsel__prev(pos); goto browse_hists; @@ -3417,7 +3417,7 @@ int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help, single_entry: if (nr_entries == 1) { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); return perf_evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt, diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 893b065971f6..3d49b916c9e4 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -5,7 +5,6 @@ #include <stdlib.h> #include <string.h> #include <linux/bitops.h> -#include "../../util/util.h" #include "../../util/debug.h" #include "../../util/map.h" #include "../../util/dso.h" diff --git a/tools/perf/ui/browsers/res_sample.c b/tools/perf/ui/browsers/res_sample.c index f16a38fea45e..76d356a18790 100644 --- a/tools/perf/ui/browsers/res_sample.c +++ b/tools/perf/ui/browsers/res_sample.c @@ -7,7 +7,7 @@ #include "config.h" #include "time-utils.h" #include "../util.h" -#include "../../util/util.h" +#include "../../util/util.h" // perf_exe() #include "../../perf.h" #include <stdlib.h> #include <string.h> diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index 586a21acc13d..fc733a6354d4 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include "../../builtin.h" #include "../../perf.h" -#include "../../util/util.h" +#include "../../util/util.h" // perf_exe() +#include "../util.h" #include "../../util/hist.h" #include "../../util/debug.h" #include "../../util/symbol.h" diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c index e166da9ec767..e40a006aead8 100644 --- a/tools/perf/ui/gtk/helpline.c +++ b/tools/perf/ui/gtk/helpline.c @@ -6,7 +6,6 @@ #include "gtk.h" #include "../ui.h" #include "../helpline.h" -#include "../../util/debug.h" static void gtk_helpline_pop(void) { diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 6c2efc10bf5c..ed1a97b2c4b0 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -8,6 +8,7 @@ #include "../string2.h" #include "gtk.h" #include <signal.h> +#include <stdlib.h> #include <linux/string.h> #define MAX_COLUMNS 32 diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c index b6ad8857da78..eea6fcde518a 100644 --- a/tools/perf/ui/gtk/progress.c +++ b/tools/perf/ui/gtk/progress.c @@ -3,7 +3,6 @@ #include "gtk.h" #include "../progress.h" -#include "util.h" static GtkWidget *dialog; static GtkWidget *progress; diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c index 1a2616b97b5c..f5eee4d66873 100644 --- a/tools/perf/ui/gtk/setup.c +++ b/tools/perf/ui/gtk/setup.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "gtk.h" -#include "../../util/debug.h" +#include <linux/compiler.h> +#include "../util.h" extern struct perf_error_ops perf_gtk_eops; diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index c2c558958b9c..c47f5c387838 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include "../util.h" -#include "../../util/debug.h" #include "gtk.h" #include <stdlib.h> diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index 54bcd08df87e..911182b3f5e6 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c @@ -3,10 +3,8 @@ #include <stdlib.h> #include <string.h> -#include "../util/debug.h" #include "helpline.h" #include "ui.h" -#include "../util/util.h" char ui_helpline__current[512]; diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 3e533de7d852..f73675500061 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -8,7 +8,6 @@ #include "../util/callchain.h" #include "../util/debug.h" #include "../util/hist.h" -#include "../util/util.h" #include "../util/sort.h" #include "../util/evsel.h" #include "../util/evlist.h" diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index c7a86b4be9f5..700335cde618 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 #include <pthread.h> #include <dlfcn.h> +#include <unistd.h> #include <subcmd/pager.h> #include "../util/debug.h" #include "../util/hist.h" -#include "../util/util.h" #include "ui.h" pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 832ca6cfbe30..5365606e9dad 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -5,6 +5,7 @@ #include "../../util/callchain.h" #include "../../util/debug.h" +#include "../../util/event.h" #include "../../util/hist.h" #include "../../util/map.h" #include "../../util/map_groups.h" diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 5f188f678c55..298d6af82fdd 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c @@ -6,7 +6,6 @@ #include <linux/kernel.h> #include <linux/string.h> -#include "../../util/debug.h" #include "../helpline.h" #include "../ui.h" #include "../libslang.h" diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index 56651a4f5aa0..e9bfe856a5de 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -2,13 +2,13 @@ #include <signal.h> #include <stdbool.h> #include <stdlib.h> +#include <unistd.h> #include <linux/kernel.h> #ifdef HAVE_BACKTRACE_SUPPORT #include <execinfo.h> #endif #include "../../util/debug.h" -#include "../../util/util.h" #include "../../perf.h" #include "../browser.h" #include "../helpline.h" diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c index 087d9ab054c8..b98dd0e31dc1 100644 --- a/tools/perf/ui/tui/util.c +++ b/tools/perf/ui/tui/util.c @@ -5,7 +5,6 @@ #include <stdlib.h> #include <sys/ttydefaults.h> -#include "../../util/debug.h" #include "../browser.h" #include "../keysyms.h" #include "../helpline.h" diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 0b4d8e0d474c..8dcfca1a882f 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -3,6 +3,7 @@ perf-y += block-range.o perf-y += build-id.o perf-y += cacheline.o perf-y += config.o +perf-y += copyfile.o perf-y += ctype.o perf-y += db-export.o perf-y += env.o @@ -10,6 +11,7 @@ perf-y += event.o perf-y += evlist.o perf-y += evsel.o perf-y += evsel_fprintf.o +perf-y += perf_event_attr_fprintf.o perf-y += evswitch.o perf-y += find_bit.o perf-y += get_current_dir_name.o @@ -86,6 +88,7 @@ perf-y += stat-display.o perf-y += record.o perf-y += srcline.o perf-y += srccode.o +perf-y += synthetic-events.o perf-y += data.o perf-y += tsc.o perf-y += cloexec.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1748f528b6e9..e830eadfca2a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -14,7 +14,7 @@ #include <bpf/btf.h> #include <bpf/libbpf.h> #include <linux/btf.h> -#include "util.h" +#include "util.h" // hex_width() #include "ui/ui.h" #include "sort.h" #include "build-id.h" @@ -34,6 +34,7 @@ #include "bpf-event.h" #include "block-range.h" #include "string2.h" +#include "util/event.h" #include "arch/common.h" #include <regex.h> #include <pthread.h> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 8a7340f6a2a2..53be12b23ff4 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -16,7 +16,6 @@ #include <linux/log2.h> #include <linux/zalloc.h> -#include "cpumap.h" #include "color.h" #include "evsel.h" #include "machine.h" diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 6f25224a3def..8470dfe9fe97 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -31,8 +31,8 @@ #include "map.h" #include "pmu.h" #include "evsel.h" -#include "cpumap.h" #include "symbol.h" +#include "util/synthetic-events.h" #include "thread_map.h" #include "asm/bug.h" #include "auxtrace.h" @@ -50,10 +50,12 @@ #include "intel-bts.h" #include "arm-spe.h" #include "s390-cpumsf.h" -#include "util.h" +#include "util/mmap.h" #include <linux/ctype.h> +#include <linux/kernel.h> #include "symbol/kallsyms.h" +#include <internal/lib.h> static bool auxtrace__dont_decode(struct perf_session *session) { @@ -1226,7 +1228,7 @@ int perf_event__process_auxtrace_error(struct perf_session *session, return 0; } -static int __auxtrace_mmap__read(struct perf_mmap *map, +static int __auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr, struct perf_tool *tool, process_auxtrace_t fn, bool snapshot, size_t snapshot_size) @@ -1337,13 +1339,13 @@ static int __auxtrace_mmap__read(struct perf_mmap *map, return 1; } -int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr, +int auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr, struct perf_tool *tool, process_auxtrace_t fn) { return __auxtrace_mmap__read(map, itr, tool, fn, false, 0); } -int auxtrace_mmap__read_snapshot(struct perf_mmap *map, +int auxtrace_mmap__read_snapshot(struct mmap *map, struct auxtrace_record *itr, struct perf_tool *tool, process_auxtrace_t fn, size_t snapshot_size) diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 37e70dc01436..f201f36bc35f 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -11,21 +11,22 @@ #include <errno.h> #include <stdbool.h> #include <stddef.h> +#include <stdio.h> // FILE #include <linux/list.h> #include <linux/perf_event.h> #include <linux/types.h> #include <asm/bitsperlong.h> #include <asm/barrier.h> -#include "event.h" - union perf_event; struct perf_session; struct evlist; struct perf_tool; -struct perf_mmap; +struct mmap; +struct perf_sample; struct option; struct record_opts; +struct perf_record_auxtrace_error; struct perf_record_auxtrace_info; struct events_stats; @@ -444,14 +445,14 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, bool per_cpu); typedef int (*process_auxtrace_t)(struct perf_tool *tool, - struct perf_mmap *map, + struct mmap *map, union perf_event *event, void *data1, size_t len1, void *data2, size_t len2); -int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr, +int auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr, struct perf_tool *tool, process_auxtrace_t fn); -int auxtrace_mmap__read_snapshot(struct perf_mmap *map, +int auxtrace_mmap__read_snapshot(struct mmap *map, struct auxtrace_record *itr, struct perf_tool *tool, process_auxtrace_t fn, size_t snapshot_size); @@ -524,10 +525,6 @@ void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int int code, int cpu, pid_t pid, pid_t tid, u64 ip, const char *msg, u64 timestamp); -int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, - struct perf_tool *tool, - struct perf_session *session, - perf_event__handler_t process); int perf_event__process_auxtrace_info(struct perf_session *session, union perf_event *event); s64 perf_event__process_auxtrace(struct perf_session *session, @@ -604,15 +601,6 @@ void auxtrace_record__free(struct auxtrace_record *itr __maybe_unused) { } -static inline int -perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr __maybe_unused, - struct perf_tool *tool __maybe_unused, - struct perf_session *session __maybe_unused, - perf_event__handler_t process __maybe_unused) -{ - return -EINVAL; -} - static inline int auxtrace_record__options(struct auxtrace_record *itr __maybe_unused, struct evlist *evlist __maybe_unused, diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 7a3d4b125323..f7ed5d122e22 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -16,6 +16,7 @@ #include "map.h" #include "evlist.h" #include "record.h" +#include "util/synthetic-events.h" #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h index a01c2fd68c03..81fdc88e6c1a 100644 --- a/tools/perf/util/bpf-event.h +++ b/tools/perf/util/bpf-event.h @@ -6,9 +6,9 @@ #include <linux/rbtree.h> #include <pthread.h> #include <api/fd/array.h> -#include "event.h" #include <stdio.h> +struct bpf_prog_info; struct machine; union perf_event; struct perf_env; @@ -33,11 +33,6 @@ struct btf_node { #ifdef HAVE_LIBBPF_SUPPORT int machine__process_bpf(struct machine *machine, union perf_event *event, struct perf_sample *sample); - -int perf_event__synthesize_bpf_events(struct perf_session *session, - perf_event__handler_t process, - struct machine *machine, - struct record_opts *opts); int bpf_event__add_sb_event(struct evlist **evlist, struct perf_env *env); void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info, @@ -51,14 +46,6 @@ static inline int machine__process_bpf(struct machine *machine __maybe_unused, return 0; } -static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused, - perf_event__handler_t process __maybe_unused, - struct machine *machine __maybe_unused, - struct record_opts *opts __maybe_unused) -{ - return 0; -} - static inline int bpf_event__add_sb_event(struct evlist **evlist __maybe_unused, struct perf_env *env __maybe_unused) { diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 37283e865352..10c187b8b8ea 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -1568,7 +1568,7 @@ struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name) return ERR_PTR(-err); } - evsel = perf_evlist__last(evlist); + evsel = evlist__last(evlist); } bpf__for_each_map_named(map, obj, tmp, name) { diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c index 9d1e090084a2..2285b1eb3128 100644 --- a/tools/perf/util/branch.c +++ b/tools/perf/util/branch.c @@ -1,5 +1,3 @@ -#include "util/util.h" -#include "util/debug.h" #include "util/map_symbol.h" #include "util/branch.h" #include <linux/kernel.h> diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h index 06f66dad0b79..88e00d268f6f 100644 --- a/tools/perf/util/branch.h +++ b/tools/perf/util/branch.h @@ -1,8 +1,15 @@ #ifndef _PERF_BRANCH_H #define _PERF_BRANCH_H 1 - +/* + * The linux/stddef.h isn't need here, but is needed for __always_inline used + * in files included from uapi/linux/perf_event.h such as + * /usr/include/linux/swab.h and /usr/include/linux/byteorder/little_endian.h, + * detected in at least musl libc, used in Alpine Linux. -acme + */ #include <stdio.h> #include <stdint.h> +#include <linux/compiler.h> +#include <linux/stddef.h> #include <linux/perf_event.h> #include <linux/types.h> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index e5fb77755d9e..c076fc7fe025 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -7,12 +7,13 @@ * Copyright (C) 2009, 2010 Red Hat Inc. * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com> */ -#include "util.h" +#include "util.h" // lsdir(), mkdir_p(), rm_rf() #include <dirent.h> #include <errno.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> +#include "util/copyfile.h" #include "dso.h" #include "build-id.h" #include "event.h" diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index c14646c1f2eb..9a9b56ed3f0a 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -23,6 +23,7 @@ #include "debug.h" #include "dso.h" +#include "event.h" #include "hist.h" #include "sort.h" #include "machine.h" diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index b042ceef4114..83398e5bbe4b 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -4,12 +4,15 @@ #include <linux/list.h> #include <linux/rbtree.h> -#include "event.h" #include "map_symbol.h" #include "branch.h" +struct addr_location; struct evsel; +struct ip_callchain; struct map; +struct perf_sample; +struct thread; #define HELP_PAD "\t\t\t\t" diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 4e904fcb2783..a12872f2856a 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <sched.h> -#include "util.h" +#include "util.h" // for sched_getcpu() #include "../perf-sys.h" #include "cloexec.h" #include "event.h" diff --git a/tools/perf/util/copyfile.c b/tools/perf/util/copyfile.c new file mode 100644 index 000000000000..3fa0db136667 --- /dev/null +++ b/tools/perf/util/copyfile.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "util/copyfile.h" +#include "util/namespaces.h" +#include <internal/lib.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi) +{ + int err = -1; + char *line = NULL; + size_t n; + FILE *from_fp, *to_fp; + struct nscookie nsc; + + nsinfo__mountns_enter(nsi, &nsc); + from_fp = fopen(from, "r"); + nsinfo__mountns_exit(&nsc); + if (from_fp == NULL) + goto out; + + to_fp = fopen(to, "w"); + if (to_fp == NULL) + goto out_fclose_from; + + while (getline(&line, &n, from_fp) > 0) + if (fputs(line, to_fp) == EOF) + goto out_fclose_to; + err = 0; +out_fclose_to: + fclose(to_fp); + free(line); +out_fclose_from: + fclose(from_fp); +out: + return err; +} + +int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) +{ + void *ptr; + loff_t pgoff; + + pgoff = off_in & ~(page_size - 1); + off_in -= pgoff; + + ptr = mmap(NULL, off_in + size, PROT_READ, MAP_PRIVATE, ifd, pgoff); + if (ptr == MAP_FAILED) + return -1; + + while (size) { + ssize_t ret = pwrite(ofd, ptr + off_in, size, off_out); + if (ret < 0 && errno == EINTR) + continue; + if (ret <= 0) + break; + + size -= ret; + off_in += ret; + off_out += ret; + } + munmap(ptr, off_in + size); + + return size ? -1 : 0; +} + +static int copyfile_mode_ns(const char *from, const char *to, mode_t mode, + struct nsinfo *nsi) +{ + int fromfd, tofd; + struct stat st; + int err; + char *tmp = NULL, *ptr = NULL; + struct nscookie nsc; + + nsinfo__mountns_enter(nsi, &nsc); + err = stat(from, &st); + nsinfo__mountns_exit(&nsc); + if (err) + goto out; + err = -1; + + /* extra 'x' at the end is to reserve space for '.' */ + if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) { + tmp = NULL; + goto out; + } + ptr = strrchr(tmp, '/'); + if (!ptr) + goto out; + ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1); + *ptr = '.'; + + tofd = mkstemp(tmp); + if (tofd < 0) + goto out; + + if (fchmod(tofd, mode)) + goto out_close_to; + + if (st.st_size == 0) { /* /proc? do it slowly... */ + err = slow_copyfile(from, tmp, nsi); + goto out_close_to; + } + + nsinfo__mountns_enter(nsi, &nsc); + fromfd = open(from, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fromfd < 0) + goto out_close_to; + + err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size); + + close(fromfd); +out_close_to: + close(tofd); + if (!err) + err = link(tmp, to); + unlink(tmp); +out: + free(tmp); + return err; +} + +int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi) +{ + return copyfile_mode_ns(from, to, 0755, nsi); +} + +int copyfile_mode(const char *from, const char *to, mode_t mode) +{ + return copyfile_mode_ns(from, to, mode, NULL); +} + +int copyfile(const char *from, const char *to) +{ + return copyfile_mode(from, to, 0755); +} diff --git a/tools/perf/util/copyfile.h b/tools/perf/util/copyfile.h new file mode 100644 index 000000000000..e85d2f22f3cc --- /dev/null +++ b/tools/perf/util/copyfile.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef PERF_COPYFILE_H_ +#define PERF_COPYFILE_H_ + +#include <linux/types.h> +#include <sys/types.h> +#include <fcntl.h> + +struct nsinfo; + +int copyfile(const char *from, const char *to); +int copyfile_mode(const char *from, const char *to, mode_t mode); +int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); +int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size); + +#endif // PERF_COPYFILE_H_ diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index 37d7c492b155..cd92a99eb89d 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -17,7 +17,6 @@ #include "cs-etm.h" #include "cs-etm-decoder.h" #include "intlist.h" -#include "util.h" /* use raw logging */ #ifdef CS_DEBUG_RAW diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 707afdbd9529..4ba0f871f086 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -35,7 +35,7 @@ #include "thread.h" #include "thread-stack.h" #include <tools/libc_compat.h> -#include "util.h" +#include "util/synthetic-events.h" #define MAX_TIMESTAMP (~0ULL) @@ -1298,7 +1298,7 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, attr.read_format = evsel->core.attr.read_format; /* create new id val to be a fixed offset from evsel id */ - id = evsel->id[0] + 1000000000; + id = evsel->core.id[0] + 1000000000; if (!id) id = 1; diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 0c268449959c..dbc772bfb04e 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -30,6 +30,7 @@ #include "machine.h" #include "config.h" #include <linux/ctype.h> +#include <linux/err.h> #define pr_N(n, fmt, ...) \ eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) @@ -1619,8 +1620,10 @@ int bt_convert__perf2ctf(const char *input, const char *path, err = -1; /* perf.data session */ session = perf_session__new(&data, 0, &c.tool); - if (!session) + if (IS_ERR(session)) { + err = PTR_ERR(session); goto free_writer; + } if (c.queue_size) { ordered_events__set_alloc_size(&session->ordered_events, diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index e75c3a279fe8..88fba2ba549f 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -13,9 +13,10 @@ #include <dirent.h> #include "data.h" -#include "util.h" +#include "util.h" // rm_rf_perf_data() #include "debug.h" #include "header.h" +#include <internal/lib.h> static void close_dir(struct perf_data_file *files, int nr) { diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index a1b59bd35519..e55114f0336f 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -17,7 +17,6 @@ #include "event.h" #include "debug.h" #include "print_binary.h" -#include "util.h" #include "target.h" #include "ui/helpline.h" #include "ui/ui.h" diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index b2deee987ffa..d25ae1c4cee9 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -3,9 +3,9 @@ #ifndef __PERF_DEBUG_H #define __PERF_DEBUG_H +#include <stdarg.h> #include <stdbool.h> #include <linux/compiler.h> -#include "../ui/util.h" extern int verbose; extern bool quiet, dump_trace; diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c index 763328c151e9..6fb7f34c0814 100644 --- a/tools/perf/util/demangle-java.c +++ b/tools/perf/util/demangle-java.c @@ -3,7 +3,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "debug.h" #include "symbol.h" #include "demangle-java.h" diff --git a/tools/perf/util/demangle-rust.c b/tools/perf/util/demangle-rust.c index 423afbbd386b..a659fc69f73a 100644 --- a/tools/perf/util/demangle-rust.c +++ b/tools/perf/util/demangle-rust.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 #include <string.h> -#include "util.h" #include "debug.h" #include "demangle-rust.h" diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c index db55eddce8cd..1b49ecee5aff 100644 --- a/tools/perf/util/dwarf-regs.c +++ b/tools/perf/util/dwarf-regs.c @@ -5,7 +5,6 @@ * Written by: Masami Hiramatsu <mhiramat@kernel.org> */ -#include <util.h> #include <debug.h> #include <dwarf-regs.h> #include <elf.h> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index d8e083d42610..db40906e2937 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -4,9 +4,10 @@ #include <linux/types.h> #include <linux/rbtree.h> -#include "cpumap.h" #include "rwsem.h" +struct perf_cpu_map; + struct cpu_topology_map { int socket_id; int die_id; diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index f4afbb858ebb..fc1e5a991008 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,16 +1,16 @@ -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <linux/kernel.h> #include <linux/types.h> +#include <perf/cpumap.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ -#include <api/fs/fs.h> #include <linux/perf_event.h> #include <linux/zalloc.h> +#include "cpumap.h" #include "dso.h" #include "event.h" #include "debug.h" @@ -24,6 +24,7 @@ #include "time-utils.h" #include <linux/ctype.h> #include "map.h" +#include "util/namespaces.h" #include "symbol.h" #include "symbol/kallsyms.h" #include "asm/bug.h" @@ -33,8 +34,6 @@ #include "tool.h" #include "../perf.h" -#define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 - static const char *perf_event__names[] = { [0] = "TOTAL", [PERF_RECORD_MMAP] = "MMAP", @@ -75,18 +74,6 @@ static const char *perf_event__names[] = { [PERF_RECORD_COMPRESSED] = "COMPRESSED", }; -static const char *perf_ns__names[] = { - [NET_NS_INDEX] = "net", - [UTS_NS_INDEX] = "uts", - [IPC_NS_INDEX] = "ipc", - [PID_NS_INDEX] = "pid", - [USER_NS_INDEX] = "user", - [MNT_NS_INDEX] = "mnt", - [CGROUP_NS_INDEX] = "cgroup", -}; - -unsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT; - const char *perf_event__name(unsigned int id) { if (id >= ARRAY_SIZE(perf_event__names)) @@ -96,775 +83,6 @@ const char *perf_event__name(unsigned int id) return perf_event__names[id]; } -static const char *perf_ns__name(unsigned int id) -{ - if (id >= ARRAY_SIZE(perf_ns__names)) - return "UNKNOWN"; - return perf_ns__names[id]; -} - -int perf_tool__process_synth_event(struct perf_tool *tool, - union perf_event *event, - struct machine *machine, - perf_event__handler_t process) -{ - struct perf_sample synth_sample = { - .pid = -1, - .tid = -1, - .time = -1, - .stream_id = -1, - .cpu = -1, - .period = 1, - .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK, - }; - - return process(tool, event, &synth_sample, machine); -}; - -/* - * Assumes that the first 4095 bytes of /proc/pid/stat contains - * the comm, tgid and ppid. - */ -static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, - pid_t *tgid, pid_t *ppid) -{ - char filename[PATH_MAX]; - char bf[4096]; - int fd; - size_t size = 0; - ssize_t n; - char *name, *tgids, *ppids; - - *tgid = -1; - *ppid = -1; - - snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - - fd = open(filename, O_RDONLY); - if (fd < 0) { - pr_debug("couldn't open %s\n", filename); - return -1; - } - - n = read(fd, bf, sizeof(bf) - 1); - close(fd); - if (n <= 0) { - pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", - pid); - return -1; - } - bf[n] = '\0'; - - name = strstr(bf, "Name:"); - tgids = strstr(bf, "Tgid:"); - ppids = strstr(bf, "PPid:"); - - if (name) { - char *nl; - - name = skip_spaces(name + 5); /* strlen("Name:") */ - nl = strchr(name, '\n'); - if (nl) - *nl = '\0'; - - size = strlen(name); - if (size >= len) - size = len - 1; - memcpy(comm, name, size); - comm[size] = '\0'; - } else { - pr_debug("Name: string not found for pid %d\n", pid); - } - - if (tgids) { - tgids += 5; /* strlen("Tgid:") */ - *tgid = atoi(tgids); - } else { - pr_debug("Tgid: string not found for pid %d\n", pid); - } - - if (ppids) { - ppids += 5; /* strlen("PPid:") */ - *ppid = atoi(ppids); - } else { - pr_debug("PPid: string not found for pid %d\n", pid); - } - - return 0; -} - -static int perf_event__prepare_comm(union perf_event *event, pid_t pid, - struct machine *machine, - pid_t *tgid, pid_t *ppid) -{ - size_t size; - - *ppid = -1; - - memset(&event->comm, 0, sizeof(event->comm)); - - if (machine__is_host(machine)) { - if (perf_event__get_comm_ids(pid, event->comm.comm, - sizeof(event->comm.comm), - tgid, ppid) != 0) { - return -1; - } - } else { - *tgid = machine->pid; - } - - if (*tgid < 0) - return -1; - - event->comm.pid = *tgid; - event->comm.header.type = PERF_RECORD_COMM; - - size = strlen(event->comm.comm) + 1; - size = PERF_ALIGN(size, sizeof(u64)); - memset(event->comm.comm + size, 0, machine->id_hdr_size); - event->comm.header.size = (sizeof(event->comm) - - (sizeof(event->comm.comm) - size) + - machine->id_hdr_size); - event->comm.tid = pid; - - return 0; -} - -pid_t perf_event__synthesize_comm(struct perf_tool *tool, - union perf_event *event, pid_t pid, - perf_event__handler_t process, - struct machine *machine) -{ - pid_t tgid, ppid; - - if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) - return -1; - - if (perf_tool__process_synth_event(tool, event, machine, process) != 0) - return -1; - - return tgid; -} - -static void perf_event__get_ns_link_info(pid_t pid, const char *ns, - struct perf_ns_link_info *ns_link_info) -{ - struct stat64 st; - char proc_ns[128]; - - sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns); - if (stat64(proc_ns, &st) == 0) { - ns_link_info->dev = st.st_dev; - ns_link_info->ino = st.st_ino; - } -} - -int perf_event__synthesize_namespaces(struct perf_tool *tool, - union perf_event *event, - pid_t pid, pid_t tgid, - perf_event__handler_t process, - struct machine *machine) -{ - u32 idx; - struct perf_ns_link_info *ns_link_info; - - if (!tool || !tool->namespace_events) - return 0; - - memset(&event->namespaces, 0, (sizeof(event->namespaces) + - (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + - machine->id_hdr_size)); - - event->namespaces.pid = tgid; - event->namespaces.tid = pid; - - event->namespaces.nr_namespaces = NR_NAMESPACES; - - ns_link_info = event->namespaces.link_info; - - for (idx = 0; idx < event->namespaces.nr_namespaces; idx++) - perf_event__get_ns_link_info(pid, perf_ns__name(idx), - &ns_link_info[idx]); - - event->namespaces.header.type = PERF_RECORD_NAMESPACES; - - event->namespaces.header.size = (sizeof(event->namespaces) + - (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + - machine->id_hdr_size); - - if (perf_tool__process_synth_event(tool, event, machine, process) != 0) - return -1; - - return 0; -} - -static int perf_event__synthesize_fork(struct perf_tool *tool, - union perf_event *event, - pid_t pid, pid_t tgid, pid_t ppid, - perf_event__handler_t process, - struct machine *machine) -{ - memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); - - /* - * for main thread set parent to ppid from status file. For other - * threads set parent pid to main thread. ie., assume main thread - * spawns all threads in a process - */ - if (tgid == pid) { - event->fork.ppid = ppid; - event->fork.ptid = ppid; - } else { - event->fork.ppid = tgid; - event->fork.ptid = tgid; - } - event->fork.pid = tgid; - event->fork.tid = pid; - event->fork.header.type = PERF_RECORD_FORK; - event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; - - event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); - - if (perf_tool__process_synth_event(tool, event, machine, process) != 0) - return -1; - - return 0; -} - -int perf_event__synthesize_mmap_events(struct perf_tool *tool, - union perf_event *event, - pid_t pid, pid_t tgid, - perf_event__handler_t process, - struct machine *machine, - bool mmap_data) -{ - char filename[PATH_MAX]; - FILE *fp; - unsigned long long t; - bool truncation = false; - unsigned long long timeout = proc_map_timeout * 1000000ULL; - int rc = 0; - const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); - int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; - - if (machine__is_default_guest(machine)) - return 0; - - snprintf(filename, sizeof(filename), "%s/proc/%d/task/%d/maps", - machine->root_dir, pid, pid); - - fp = fopen(filename, "r"); - if (fp == NULL) { - /* - * We raced with a task exiting - just return: - */ - pr_debug("couldn't open %s\n", filename); - return -1; - } - - event->header.type = PERF_RECORD_MMAP2; - t = rdclock(); - - while (1) { - char bf[BUFSIZ]; - char prot[5]; - char execname[PATH_MAX]; - char anonstr[] = "//anon"; - unsigned int ino; - size_t size; - ssize_t n; - - if (fgets(bf, sizeof(bf), fp) == NULL) - break; - - if ((rdclock() - t) > timeout) { - pr_warning("Reading %s time out. " - "You may want to increase " - "the time limit by --proc-map-timeout\n", - filename); - truncation = true; - goto out; - } - - /* ensure null termination since stack will be reused. */ - strcpy(execname, ""); - - /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = sscanf(bf, "%"PRI_lx64"-%"PRI_lx64" %s %"PRI_lx64" %x:%x %u %[^\n]\n", - &event->mmap2.start, &event->mmap2.len, prot, - &event->mmap2.pgoff, &event->mmap2.maj, - &event->mmap2.min, - &ino, execname); - - /* - * Anon maps don't have the execname. - */ - if (n < 7) - continue; - - event->mmap2.ino = (u64)ino; - - /* - * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c - */ - if (machine__is_host(machine)) - event->header.misc = PERF_RECORD_MISC_USER; - else - event->header.misc = PERF_RECORD_MISC_GUEST_USER; - - /* map protection and flags bits */ - event->mmap2.prot = 0; - event->mmap2.flags = 0; - if (prot[0] == 'r') - event->mmap2.prot |= PROT_READ; - if (prot[1] == 'w') - event->mmap2.prot |= PROT_WRITE; - if (prot[2] == 'x') - event->mmap2.prot |= PROT_EXEC; - - if (prot[3] == 's') - event->mmap2.flags |= MAP_SHARED; - else - event->mmap2.flags |= MAP_PRIVATE; - - if (prot[2] != 'x') { - if (!mmap_data || prot[0] != 'r') - continue; - - event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; - } - -out: - if (truncation) - event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; - - if (!strcmp(execname, "")) - strcpy(execname, anonstr); - - if (hugetlbfs_mnt_len && - !strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) { - strcpy(execname, anonstr); - event->mmap2.flags |= MAP_HUGETLB; - } - - size = strlen(execname) + 1; - memcpy(event->mmap2.filename, execname, size); - size = PERF_ALIGN(size, sizeof(u64)); - event->mmap2.len -= event->mmap.start; - event->mmap2.header.size = (sizeof(event->mmap2) - - (sizeof(event->mmap2.filename) - size)); - memset(event->mmap2.filename + size, 0, machine->id_hdr_size); - event->mmap2.header.size += machine->id_hdr_size; - event->mmap2.pid = tgid; - event->mmap2.tid = pid; - - if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { - rc = -1; - break; - } - - if (truncation) - break; - } - - fclose(fp); - return rc; -} - -int perf_event__synthesize_modules(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) -{ - int rc = 0; - struct map *pos; - struct maps *maps = machine__kernel_maps(machine); - union perf_event *event = zalloc((sizeof(event->mmap) + - machine->id_hdr_size)); - if (event == NULL) { - pr_debug("Not enough memory synthesizing mmap event " - "for kernel modules\n"); - return -1; - } - - event->header.type = PERF_RECORD_MMAP; - - /* - * kernel uses 0 for user space maps, see kernel/perf_event.c - * __perf_event_mmap - */ - if (machine__is_host(machine)) - event->header.misc = PERF_RECORD_MISC_KERNEL; - else - event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; - - for (pos = maps__first(maps); pos; pos = map__next(pos)) { - size_t size; - - if (!__map__is_kmodule(pos)) - continue; - - size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); - event->mmap.header.type = PERF_RECORD_MMAP; - event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, machine->id_hdr_size); - event->mmap.header.size += machine->id_hdr_size; - event->mmap.start = pos->start; - event->mmap.len = pos->end - pos->start; - event->mmap.pid = machine->pid; - - memcpy(event->mmap.filename, pos->dso->long_name, - pos->dso->long_name_len + 1); - if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { - rc = -1; - break; - } - } - - free(event); - return rc; -} - -static int __event__synthesize_thread(union perf_event *comm_event, - union perf_event *mmap_event, - union perf_event *fork_event, - union perf_event *namespaces_event, - pid_t pid, int full, - perf_event__handler_t process, - struct perf_tool *tool, - struct machine *machine, - bool mmap_data) -{ - char filename[PATH_MAX]; - DIR *tasks; - struct dirent *dirent; - pid_t tgid, ppid; - int rc = 0; - - /* special case: only send one comm event using passed in pid */ - if (!full) { - tgid = perf_event__synthesize_comm(tool, comm_event, pid, - process, machine); - - if (tgid == -1) - return -1; - - if (perf_event__synthesize_namespaces(tool, namespaces_event, pid, - tgid, process, machine) < 0) - return -1; - - /* - * send mmap only for thread group leader - * see thread__init_map_groups - */ - if (pid == tgid && - perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, - process, machine, mmap_data)) - return -1; - - return 0; - } - - if (machine__is_default_guest(machine)) - return 0; - - snprintf(filename, sizeof(filename), "%s/proc/%d/task", - machine->root_dir, pid); - - tasks = opendir(filename); - if (tasks == NULL) { - pr_debug("couldn't open %s\n", filename); - return 0; - } - - while ((dirent = readdir(tasks)) != NULL) { - char *end; - pid_t _pid; - - _pid = strtol(dirent->d_name, &end, 10); - if (*end) - continue; - - rc = -1; - if (perf_event__prepare_comm(comm_event, _pid, machine, - &tgid, &ppid) != 0) - break; - - if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, - ppid, process, machine) < 0) - break; - - if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, - tgid, process, machine) < 0) - break; - - /* - * Send the prepared comm event - */ - if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) - break; - - rc = 0; - if (_pid == pid) { - /* process the parent's maps too */ - rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, - process, machine, mmap_data); - if (rc) - break; - } - } - - closedir(tasks); - return rc; -} - -int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct perf_thread_map *threads, - perf_event__handler_t process, - struct machine *machine, - bool mmap_data) -{ - union perf_event *comm_event, *mmap_event, *fork_event; - union perf_event *namespaces_event; - int err = -1, thread, j; - - comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); - if (comm_event == NULL) - goto out; - - mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); - if (mmap_event == NULL) - goto out_free_comm; - - fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); - if (fork_event == NULL) - goto out_free_mmap; - - namespaces_event = malloc(sizeof(namespaces_event->namespaces) + - (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + - machine->id_hdr_size); - if (namespaces_event == NULL) - goto out_free_fork; - - err = 0; - for (thread = 0; thread < threads->nr; ++thread) { - if (__event__synthesize_thread(comm_event, mmap_event, - fork_event, namespaces_event, - perf_thread_map__pid(threads, thread), 0, - process, tool, machine, - mmap_data)) { - err = -1; - break; - } - - /* - * comm.pid is set to thread group id by - * perf_event__synthesize_comm - */ - if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { - bool need_leader = true; - - /* is thread group leader in thread_map? */ - for (j = 0; j < threads->nr; ++j) { - if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { - need_leader = false; - break; - } - } - - /* if not, generate events for it */ - if (need_leader && - __event__synthesize_thread(comm_event, mmap_event, - fork_event, namespaces_event, - comm_event->comm.pid, 0, - process, tool, machine, - mmap_data)) { - err = -1; - break; - } - } - } - free(namespaces_event); -out_free_fork: - free(fork_event); -out_free_mmap: - free(mmap_event); -out_free_comm: - free(comm_event); -out: - return err; -} - -static int __perf_event__synthesize_threads(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine, - bool mmap_data, - struct dirent **dirent, - int start, - int num) -{ - union perf_event *comm_event, *mmap_event, *fork_event; - union perf_event *namespaces_event; - int err = -1; - char *end; - pid_t pid; - int i; - - comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); - if (comm_event == NULL) - goto out; - - mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); - if (mmap_event == NULL) - goto out_free_comm; - - fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); - if (fork_event == NULL) - goto out_free_mmap; - - namespaces_event = malloc(sizeof(namespaces_event->namespaces) + - (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + - machine->id_hdr_size); - if (namespaces_event == NULL) - goto out_free_fork; - - for (i = start; i < start + num; i++) { - if (!isdigit(dirent[i]->d_name[0])) - continue; - - pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); - /* only interested in proper numerical dirents */ - if (*end) - continue; - /* - * We may race with exiting thread, so don't stop just because - * one thread couldn't be synthesized. - */ - __event__synthesize_thread(comm_event, mmap_event, fork_event, - namespaces_event, pid, 1, process, - tool, machine, mmap_data); - } - err = 0; - - free(namespaces_event); -out_free_fork: - free(fork_event); -out_free_mmap: - free(mmap_event); -out_free_comm: - free(comm_event); -out: - return err; -} - -struct synthesize_threads_arg { - struct perf_tool *tool; - perf_event__handler_t process; - struct machine *machine; - bool mmap_data; - struct dirent **dirent; - int num; - int start; -}; - -static void *synthesize_threads_worker(void *arg) -{ - struct synthesize_threads_arg *args = arg; - - __perf_event__synthesize_threads(args->tool, args->process, - args->machine, args->mmap_data, - args->dirent, - args->start, args->num); - return NULL; -} - -int perf_event__synthesize_threads(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine, - bool mmap_data, - unsigned int nr_threads_synthesize) -{ - struct synthesize_threads_arg *args = NULL; - pthread_t *synthesize_threads = NULL; - char proc_path[PATH_MAX]; - struct dirent **dirent; - int num_per_thread; - int m, n, i, j; - int thread_nr; - int base = 0; - int err = -1; - - - if (machine__is_default_guest(machine)) - return 0; - - snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); - n = scandir(proc_path, &dirent, 0, alphasort); - if (n < 0) - return err; - - if (nr_threads_synthesize == UINT_MAX) - thread_nr = sysconf(_SC_NPROCESSORS_ONLN); - else - thread_nr = nr_threads_synthesize; - - if (thread_nr <= 1) { - err = __perf_event__synthesize_threads(tool, process, - machine, mmap_data, - dirent, base, n); - goto free_dirent; - } - if (thread_nr > n) - thread_nr = n; - - synthesize_threads = calloc(sizeof(pthread_t), thread_nr); - if (synthesize_threads == NULL) - goto free_dirent; - - args = calloc(sizeof(*args), thread_nr); - if (args == NULL) - goto free_threads; - - num_per_thread = n / thread_nr; - m = n % thread_nr; - for (i = 0; i < thread_nr; i++) { - args[i].tool = tool; - args[i].process = process; - args[i].machine = machine; - args[i].mmap_data = mmap_data; - args[i].dirent = dirent; - } - for (i = 0; i < m; i++) { - args[i].num = num_per_thread + 1; - args[i].start = i * args[i].num; - } - if (i != 0) - base = args[i-1].start + args[i-1].num; - for (j = i; j < thread_nr; j++) { - args[j].num = num_per_thread; - args[j].start = base + (j - i) * args[i].num; - } - - for (i = 0; i < thread_nr; i++) { - if (pthread_create(&synthesize_threads[i], NULL, - synthesize_threads_worker, &args[i])) - goto out_join; - } - err = 0; -out_join: - for (i = 0; i < thread_nr; i++) - pthread_join(synthesize_threads[i], NULL); - free(args); -free_threads: - free(synthesize_threads); -free_dirent: - for (i = 0; i < n; i++) - zfree(&dirent[i]); - free(dirent); - - return err; -} - struct process_symbol_args { const char *name; u64 start; @@ -899,327 +117,6 @@ int kallsyms__get_function_start(const char *kallsyms_filename, return 0; } -int __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, - perf_event__handler_t process __maybe_unused, - struct machine *machine __maybe_unused) -{ - return 0; -} - -static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) -{ - size_t size; - struct map *map = machine__kernel_map(machine); - struct kmap *kmap; - int err; - union perf_event *event; - - if (map == NULL) - return -1; - - kmap = map__kmap(map); - if (!kmap->ref_reloc_sym) - return -1; - - /* - * We should get this from /sys/kernel/sections/.text, but till that is - * available use this, and after it is use this as a fallback for older - * kernels. - */ - event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); - if (event == NULL) { - pr_debug("Not enough memory synthesizing mmap event " - "for kernel modules\n"); - return -1; - } - - if (machine__is_host(machine)) { - /* - * kernel uses PERF_RECORD_MISC_USER for user space maps, - * see kernel/perf_event.c __perf_event_mmap - */ - event->header.misc = PERF_RECORD_MISC_KERNEL; - } else { - event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; - } - - size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), - "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; - size = PERF_ALIGN(size, sizeof(u64)); - event->mmap.header.type = PERF_RECORD_MMAP; - event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); - event->mmap.pgoff = kmap->ref_reloc_sym->addr; - event->mmap.start = map->start; - event->mmap.len = map->end - event->mmap.start; - event->mmap.pid = machine->pid; - - err = perf_tool__process_synth_event(tool, event, machine, process); - free(event); - - return err; -} - -int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) -{ - int err; - - err = __perf_event__synthesize_kernel_mmap(tool, process, machine); - if (err < 0) - return err; - - return perf_event__synthesize_extra_kmaps(tool, process, machine); -} - -int perf_event__synthesize_thread_map2(struct perf_tool *tool, - struct perf_thread_map *threads, - perf_event__handler_t process, - struct machine *machine) -{ - union perf_event *event; - int i, err, size; - - size = sizeof(event->thread_map); - size += threads->nr * sizeof(event->thread_map.entries[0]); - - event = zalloc(size); - if (!event) - return -ENOMEM; - - event->header.type = PERF_RECORD_THREAD_MAP; - event->header.size = size; - event->thread_map.nr = threads->nr; - - for (i = 0; i < threads->nr; i++) { - struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; - char *comm = perf_thread_map__comm(threads, i); - - if (!comm) - comm = (char *) ""; - - entry->pid = perf_thread_map__pid(threads, i); - strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); - } - - err = process(tool, event, NULL, machine); - - free(event); - return err; -} - -static void synthesize_cpus(struct cpu_map_entries *cpus, - struct perf_cpu_map *map) -{ - int i; - - cpus->nr = map->nr; - - for (i = 0; i < map->nr; i++) - cpus->cpu[i] = map->map[i]; -} - -static void synthesize_mask(struct perf_record_record_cpu_map *mask, - struct perf_cpu_map *map, int max) -{ - int i; - - mask->nr = BITS_TO_LONGS(max); - mask->long_size = sizeof(long); - - for (i = 0; i < map->nr; i++) - set_bit(map->map[i], mask->mask); -} - -static size_t cpus_size(struct perf_cpu_map *map) -{ - return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); -} - -static size_t mask_size(struct perf_cpu_map *map, int *max) -{ - int i; - - *max = 0; - - for (i = 0; i < map->nr; i++) { - /* bit possition of the cpu is + 1 */ - int bit = map->map[i] + 1; - - if (bit > *max) - *max = bit; - } - - return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); -} - -void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) -{ - size_t size_cpus, size_mask; - bool is_dummy = perf_cpu_map__empty(map); - - /* - * Both array and mask data have variable size based - * on the number of cpus and their actual values. - * The size of the 'struct perf_record_cpu_map_data' is: - * - * array = size of 'struct cpu_map_entries' + - * number of cpus * sizeof(u64) - * - * mask = size of 'struct perf_record_record_cpu_map' + - * maximum cpu bit converted to size of longs - * - * and finaly + the size of 'struct perf_record_cpu_map_data'. - */ - size_cpus = cpus_size(map); - size_mask = mask_size(map, max); - - if (is_dummy || (size_cpus < size_mask)) { - *size += size_cpus; - *type = PERF_CPU_MAP__CPUS; - } else { - *size += size_mask; - *type = PERF_CPU_MAP__MASK; - } - - *size += sizeof(struct perf_record_cpu_map_data); - *size = PERF_ALIGN(*size, sizeof(u64)); - return zalloc(*size); -} - -void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, - u16 type, int max) -{ - data->type = type; - - switch (type) { - case PERF_CPU_MAP__CPUS: - synthesize_cpus((struct cpu_map_entries *) data->data, map); - break; - case PERF_CPU_MAP__MASK: - synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); - default: - break; - }; -} - -static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) -{ - size_t size = sizeof(struct perf_record_cpu_map); - struct perf_record_cpu_map *event; - int max; - u16 type; - - event = cpu_map_data__alloc(map, &size, &type, &max); - if (!event) - return NULL; - - event->header.type = PERF_RECORD_CPU_MAP; - event->header.size = size; - event->data.type = type; - - cpu_map_data__synthesize(&event->data, map, type, max); - return event; -} - -int perf_event__synthesize_cpu_map(struct perf_tool *tool, - struct perf_cpu_map *map, - perf_event__handler_t process, - struct machine *machine) -{ - struct perf_record_cpu_map *event; - int err; - - event = cpu_map_event__new(map); - if (!event) - return -ENOMEM; - - err = process(tool, (union perf_event *) event, NULL, machine); - - free(event); - return err; -} - -int perf_event__synthesize_stat_config(struct perf_tool *tool, - struct perf_stat_config *config, - perf_event__handler_t process, - struct machine *machine) -{ - struct perf_record_stat_config *event; - int size, i = 0, err; - - size = sizeof(*event); - size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); - - event = zalloc(size); - if (!event) - return -ENOMEM; - - event->header.type = PERF_RECORD_STAT_CONFIG; - event->header.size = size; - event->nr = PERF_STAT_CONFIG_TERM__MAX; - -#define ADD(__term, __val) \ - event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ - event->data[i].val = __val; \ - i++; - - ADD(AGGR_MODE, config->aggr_mode) - ADD(INTERVAL, config->interval) - ADD(SCALE, config->scale) - - WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, - "stat config terms unbalanced\n"); -#undef ADD - - err = process(tool, (union perf_event *) event, NULL, machine); - - free(event); - return err; -} - -int perf_event__synthesize_stat(struct perf_tool *tool, - u32 cpu, u32 thread, u64 id, - struct perf_counts_values *count, - perf_event__handler_t process, - struct machine *machine) -{ - struct perf_record_stat event; - - event.header.type = PERF_RECORD_STAT; - event.header.size = sizeof(event); - event.header.misc = 0; - - event.id = id; - event.cpu = cpu; - event.thread = thread; - event.val = count->val; - event.ena = count->ena; - event.run = count->run; - - return process(tool, (union perf_event *) &event, NULL, machine); -} - -int perf_event__synthesize_stat_round(struct perf_tool *tool, - u64 evtime, u64 type, - perf_event__handler_t process, - struct machine *machine) -{ - struct perf_record_stat_round event; - - event.header.type = PERF_RECORD_STAT_ROUND; - event.header.size = sizeof(event); - event.header.misc = 0; - - event.time = evtime; - event.type = type; - - return process(tool, (union perf_event *) &event, NULL, machine); -} - void perf_event__read_stat_config(struct perf_stat_config *config, struct perf_record_stat_config *event) { diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 47ad81d47b1a..a0a0c91cde4a 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -279,54 +279,13 @@ enum { void perf_event__print_totals(void); -struct perf_tool; -struct perf_thread_map; struct perf_cpu_map; +struct perf_record_stat_config; struct perf_stat_config; -struct perf_counts_values; - -typedef int (*perf_event__handler_t)(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); +struct perf_tool; -int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct perf_thread_map *threads, - perf_event__handler_t process, - struct machine *machine, bool mmap_data); -int perf_event__synthesize_thread_map2(struct perf_tool *tool, - struct perf_thread_map *threads, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_cpu_map(struct perf_tool *tool, - struct perf_cpu_map *cpus, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_threads(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine, bool mmap_data, - unsigned int nr_threads_synthesize); -int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_stat_config(struct perf_tool *tool, - struct perf_stat_config *config, - perf_event__handler_t process, - struct machine *machine); void perf_event__read_stat_config(struct perf_stat_config *config, struct perf_record_stat_config *event); -int perf_event__synthesize_stat(struct perf_tool *tool, - u32 cpu, u32 thread, u64 id, - struct perf_counts_values *count, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_stat_round(struct perf_tool *tool, - u64 time, u64 type, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_modules(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); int perf_event__process_comm(struct perf_tool *tool, union perf_event *event, @@ -380,10 +339,6 @@ int perf_event__process_bpf(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_tool__process_synth_event(struct perf_tool *tool, - union perf_event *event, - struct machine *machine, - perf_event__handler_t process); int perf_event__process(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -405,34 +360,6 @@ void thread__resolve(struct thread *thread, struct addr_location *al, const char *perf_event__name(unsigned int id); -size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, - u64 read_format); -int perf_event__synthesize_sample(union perf_event *event, u64 type, - u64 read_format, - const struct perf_sample *sample); - -pid_t perf_event__synthesize_comm(struct perf_tool *tool, - union perf_event *event, pid_t pid, - perf_event__handler_t process, - struct machine *machine); - -int perf_event__synthesize_namespaces(struct perf_tool *tool, - union perf_event *event, - pid_t pid, pid_t tgid, - perf_event__handler_t process, - struct machine *machine); - -int perf_event__synthesize_mmap_events(struct perf_tool *tool, - union perf_event *event, - pid_t pid, pid_t tgid, - perf_event__handler_t process, - struct machine *machine, - bool mmap_data); - -int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); - size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 095924aa186b..d277a98e62df 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -10,13 +10,14 @@ #include <inttypes.h> #include <poll.h> #include "cpumap.h" +#include "util/mmap.h" #include "thread_map.h" #include "target.h" #include "evlist.h" #include "evsel.h" #include "debug.h" #include "units.h" -#include "util.h" +#include <internal/lib.h> // page_size #include "../perf.h" #include "asm/bug.h" #include "bpf-event.h" @@ -49,18 +50,14 @@ int sigqueue(pid_t pid, int sig, const union sigval value); #endif #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) -#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) +#define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y) void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, struct perf_thread_map *threads) { - int i; - - for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) - INIT_HLIST_HEAD(&evlist->heads[i]); perf_evlist__init(&evlist->core); perf_evlist__set_maps(&evlist->core, cpus, threads); - fdarray__init(&evlist->pollfd, 64); + fdarray__init(&evlist->core.pollfd, 64); evlist->workload.pid = -1; evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; } @@ -108,7 +105,7 @@ struct evlist *perf_evlist__new_dummy(void) */ void perf_evlist__set_id_pos(struct evlist *evlist) { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); evlist->id_pos = first->id_pos; evlist->is_pos = first->is_pos; @@ -124,7 +121,7 @@ static void perf_evlist__update_id_pos(struct evlist *evlist) perf_evlist__set_id_pos(evlist); } -static void perf_evlist__purge(struct evlist *evlist) +static void evlist__purge(struct evlist *evlist) { struct evsel *pos, *n; @@ -137,11 +134,11 @@ static void perf_evlist__purge(struct evlist *evlist) evlist->core.nr_entries = 0; } -void perf_evlist__exit(struct evlist *evlist) +void evlist__exit(struct evlist *evlist) { zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); - fdarray__exit(&evlist->pollfd); + fdarray__exit(&evlist->core.pollfd); } void evlist__delete(struct evlist *evlist) @@ -149,14 +146,14 @@ void evlist__delete(struct evlist *evlist) if (evlist == NULL) return; - perf_evlist__munmap(evlist); + evlist__munmap(evlist); evlist__close(evlist); perf_cpu_map__put(evlist->core.cpus); perf_thread_map__put(evlist->core.threads); evlist->core.cpus = NULL; evlist->core.threads = NULL; - perf_evlist__purge(evlist); - perf_evlist__exit(evlist); + evlist__purge(evlist); + evlist__exit(evlist); free(evlist); } @@ -318,7 +315,7 @@ int perf_evlist__add_newtp(struct evlist *evlist, static int perf_evlist__nr_threads(struct evlist *evlist, struct evsel *evsel) { - if (evsel->system_wide) + if (evsel->core.system_wide) return 1; else return perf_thread_map__nr(evlist->core.threads); @@ -401,128 +398,29 @@ int perf_evlist__enable_event_idx(struct evlist *evlist, return perf_evlist__enable_event_thread(evlist, evsel, idx); } -int perf_evlist__alloc_pollfd(struct evlist *evlist) +int evlist__add_pollfd(struct evlist *evlist, int fd) { - int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); - int nr_threads = perf_thread_map__nr(evlist->core.threads); - int nfds = 0; - struct evsel *evsel; - - evlist__for_each_entry(evlist, evsel) { - if (evsel->system_wide) - nfds += nr_cpus; - else - nfds += nr_cpus * nr_threads; - } - - if (fdarray__available_entries(&evlist->pollfd) < nfds && - fdarray__grow(&evlist->pollfd, nfds) < 0) - return -ENOMEM; - - return 0; -} - -static int __perf_evlist__add_pollfd(struct evlist *evlist, int fd, - struct perf_mmap *map, short revent) -{ - int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); - /* - * Save the idx so that when we filter out fds POLLHUP'ed we can - * close the associated evlist->mmap[] entry. - */ - if (pos >= 0) { - evlist->pollfd.priv[pos].ptr = map; - - fcntl(fd, F_SETFL, O_NONBLOCK); - } - - return pos; -} - -int perf_evlist__add_pollfd(struct evlist *evlist, int fd) -{ - return __perf_evlist__add_pollfd(evlist, fd, NULL, POLLIN); + return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN); } static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, void *arg __maybe_unused) { - struct perf_mmap *map = fda->priv[fd].ptr; + struct mmap *map = fda->priv[fd].ptr; if (map) perf_mmap__put(map); } -int perf_evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask) +int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask) { - return fdarray__filter(&evlist->pollfd, revents_and_mask, + return fdarray__filter(&evlist->core.pollfd, revents_and_mask, perf_evlist__munmap_filtered, NULL); } -int perf_evlist__poll(struct evlist *evlist, int timeout) +int evlist__poll(struct evlist *evlist, int timeout) { - return fdarray__poll(&evlist->pollfd, timeout); -} - -static void perf_evlist__id_hash(struct evlist *evlist, - struct evsel *evsel, - int cpu, int thread, u64 id) -{ - int hash; - struct perf_sample_id *sid = SID(evsel, cpu, thread); - - sid->id = id; - sid->evsel = evsel; - hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); - hlist_add_head(&sid->node, &evlist->heads[hash]); -} - -void perf_evlist__id_add(struct evlist *evlist, struct evsel *evsel, - int cpu, int thread, u64 id) -{ - perf_evlist__id_hash(evlist, evsel, cpu, thread, id); - evsel->id[evsel->ids++] = id; -} - -int perf_evlist__id_add_fd(struct evlist *evlist, - struct evsel *evsel, - int cpu, int thread, int fd) -{ - u64 read_data[4] = { 0, }; - int id_idx = 1; /* The first entry is the counter value */ - u64 id; - int ret; - - ret = ioctl(fd, PERF_EVENT_IOC_ID, &id); - if (!ret) - goto add; - - if (errno != ENOTTY) - return -1; - - /* Legacy way to get event id.. All hail to old kernels! */ - - /* - * This way does not work with group format read, so bail - * out in that case. - */ - if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) - return -1; - - if (!(evsel->core.attr.read_format & PERF_FORMAT_ID) || - read(fd, &read_data, sizeof(read_data)) == -1) - return -1; - - if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - ++id_idx; - if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - ++id_idx; - - id = read_data[id_idx]; - - add: - perf_evlist__id_add(evlist, evsel, cpu, thread, id); - return 0; + return perf_evlist__poll(&evlist->core, timeout); } static void perf_evlist__set_sid_idx(struct evlist *evlist, @@ -535,7 +433,7 @@ static void perf_evlist__set_sid_idx(struct evlist *evlist, sid->cpu = evlist->core.cpus->map[cpu]; else sid->cpu = -1; - if (!evsel->system_wide && evlist->core.threads && thread >= 0) + if (!evsel->core.system_wide && evlist->core.threads && thread >= 0) sid->tid = perf_thread_map__pid(evlist->core.threads, thread); else sid->tid = -1; @@ -548,7 +446,7 @@ struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id) int hash; hash = hash_64(id, PERF_EVLIST__HLIST_BITS); - head = &evlist->heads[hash]; + head = &evlist->core.heads[hash]; hlist_for_each_entry(sid, head, node) if (sid->id == id) @@ -562,14 +460,14 @@ struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id) struct perf_sample_id *sid; if (evlist->core.nr_entries == 1 || !id) - return perf_evlist__first(evlist); + return evlist__first(evlist); sid = perf_evlist__id2sid(evlist, id); if (sid) - return sid->evsel; + return container_of(sid->evsel, struct evsel, core); if (!perf_evlist__sample_id_all(evlist)) - return perf_evlist__first(evlist); + return evlist__first(evlist); return NULL; } @@ -584,7 +482,7 @@ struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist, sid = perf_evlist__id2sid(evlist, id); if (sid) - return sid->evsel; + return container_of(sid->evsel, struct evsel, core); return NULL; } @@ -613,7 +511,7 @@ static int perf_evlist__event2id(struct evlist *evlist, struct evsel *perf_evlist__event2evsel(struct evlist *evlist, union perf_event *event) { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); struct hlist_head *head; struct perf_sample_id *sid; int hash; @@ -634,11 +532,11 @@ struct evsel *perf_evlist__event2evsel(struct evlist *evlist, return first; hash = hash_64(id, PERF_EVLIST__HLIST_BITS); - head = &evlist->heads[hash]; + head = &evlist->core.heads[hash]; hlist_for_each_entry(sid, head, node) { if (sid->id == id) - return sid->evsel; + return container_of(sid->evsel, struct evsel, core); } return NULL; } @@ -650,8 +548,8 @@ static int perf_evlist__set_paused(struct evlist *evlist, bool value) if (!evlist->overwrite_mmap) return 0; - for (i = 0; i < evlist->nr_mmaps; i++) { - int fd = evlist->overwrite_mmap[i].fd; + for (i = 0; i < evlist->core.nr_mmaps; i++) { + int fd = evlist->overwrite_mmap[i].core.fd; int err; if (fd < 0) @@ -673,42 +571,42 @@ static int perf_evlist__resume(struct evlist *evlist) return perf_evlist__set_paused(evlist, false); } -static void perf_evlist__munmap_nofree(struct evlist *evlist) +static void evlist__munmap_nofree(struct evlist *evlist) { int i; if (evlist->mmap) - for (i = 0; i < evlist->nr_mmaps; i++) + for (i = 0; i < evlist->core.nr_mmaps; i++) perf_mmap__munmap(&evlist->mmap[i]); if (evlist->overwrite_mmap) - for (i = 0; i < evlist->nr_mmaps; i++) + for (i = 0; i < evlist->core.nr_mmaps; i++) perf_mmap__munmap(&evlist->overwrite_mmap[i]); } -void perf_evlist__munmap(struct evlist *evlist) +void evlist__munmap(struct evlist *evlist) { - perf_evlist__munmap_nofree(evlist); + evlist__munmap_nofree(evlist); zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); } -static struct perf_mmap *perf_evlist__alloc_mmap(struct evlist *evlist, - bool overwrite) +static struct mmap *evlist__alloc_mmap(struct evlist *evlist, + bool overwrite) { int i; - struct perf_mmap *map; + struct mmap *map; - evlist->nr_mmaps = perf_cpu_map__nr(evlist->core.cpus); + evlist->core.nr_mmaps = perf_cpu_map__nr(evlist->core.cpus); if (perf_cpu_map__empty(evlist->core.cpus)) - evlist->nr_mmaps = perf_thread_map__nr(evlist->core.threads); - map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); + evlist->core.nr_mmaps = perf_thread_map__nr(evlist->core.threads); + map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap)); if (!map) return NULL; - for (i = 0; i < evlist->nr_mmaps; i++) { - map[i].fd = -1; - map[i].overwrite = overwrite; + for (i = 0; i < evlist->core.nr_mmaps; i++) { + map[i].core.fd = -1; + map[i].core.overwrite = overwrite; /* * When the perf_mmap() call is made we grab one refcount, plus * one extra to let perf_mmap__consume() get the last @@ -718,7 +616,7 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct evlist *evlist, * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and * thus does perf_mmap__get() on it. */ - refcount_set(&map[i].refcnt, 0); + refcount_set(&map[i].core.refcnt, 0); } return map; } @@ -732,7 +630,7 @@ perf_evlist__should_poll(struct evlist *evlist __maybe_unused, return true; } -static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, +static int evlist__mmap_per_evsel(struct evlist *evlist, int idx, struct mmap_params *mp, int cpu_idx, int thread, int *_output, int *_output_overwrite) { @@ -741,7 +639,7 @@ static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, int evlist_cpu = cpu_map__cpu(evlist->core.cpus, cpu_idx); evlist__for_each_entry(evlist, evsel) { - struct perf_mmap *maps = evlist->mmap; + struct mmap *maps = evlist->mmap; int *output = _output; int fd; int cpu; @@ -752,7 +650,7 @@ static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, maps = evlist->overwrite_mmap; if (!maps) { - maps = perf_evlist__alloc_mmap(evlist, true); + maps = evlist__alloc_mmap(evlist, true); if (!maps) return -1; evlist->overwrite_mmap = maps; @@ -762,7 +660,7 @@ static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, mp->prot &= ~PROT_WRITE; } - if (evsel->system_wide && thread) + if (evsel->core.system_wide && thread) continue; cpu = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu); @@ -792,14 +690,14 @@ static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, * other events, so it should not need to be polled anyway. * Therefore don't add it for polling. */ - if (!evsel->system_wide && - __perf_evlist__add_pollfd(evlist, fd, &maps[idx], revent) < 0) { + if (!evsel->core.system_wide && + perf_evlist__add_pollfd(&evlist->core, fd, &maps[idx], revent) < 0) { perf_mmap__put(&maps[idx]); return -1; } if (evsel->core.attr.read_format & PERF_FORMAT_ID) { - if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread, + if (perf_evlist__id_add_fd(&evlist->core, &evsel->core, cpu, thread, fd) < 0) return -1; perf_evlist__set_sid_idx(evlist, evsel, idx, cpu, @@ -810,7 +708,7 @@ static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, return 0; } -static int perf_evlist__mmap_per_cpu(struct evlist *evlist, +static int evlist__mmap_per_cpu(struct evlist *evlist, struct mmap_params *mp) { int cpu, thread; @@ -826,7 +724,7 @@ static int perf_evlist__mmap_per_cpu(struct evlist *evlist, true); for (thread = 0; thread < nr_threads; thread++) { - if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu, + if (evlist__mmap_per_evsel(evlist, cpu, mp, cpu, thread, &output, &output_overwrite)) goto out_unmap; } @@ -835,11 +733,11 @@ static int perf_evlist__mmap_per_cpu(struct evlist *evlist, return 0; out_unmap: - perf_evlist__munmap_nofree(evlist); + evlist__munmap_nofree(evlist); return -1; } -static int perf_evlist__mmap_per_thread(struct evlist *evlist, +static int evlist__mmap_per_thread(struct evlist *evlist, struct mmap_params *mp) { int thread; @@ -853,7 +751,7 @@ static int perf_evlist__mmap_per_thread(struct evlist *evlist, auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread, false); - if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, + if (evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, &output, &output_overwrite)) goto out_unmap; } @@ -861,7 +759,7 @@ static int perf_evlist__mmap_per_thread(struct evlist *evlist, return 0; out_unmap: - perf_evlist__munmap_nofree(evlist); + evlist__munmap_nofree(evlist); return -1; } @@ -888,7 +786,7 @@ unsigned long perf_event_mlock_kb_in_pages(void) return pages; } -size_t perf_evlist__mmap_size(unsigned long pages) +size_t evlist__mmap_size(unsigned long pages) { if (pages == UINT_MAX) pages = perf_event_mlock_kb_in_pages(); @@ -971,7 +869,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, } /** - * perf_evlist__mmap_ex - Create mmaps to receive events. + * evlist__mmap_ex - Create mmaps to receive events. * @evlist: list of events * @pages: map length in pages * @overwrite: overwrite older events? @@ -979,7 +877,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, * @auxtrace_overwrite - overwrite older auxtrace data? * * If @overwrite is %false the user needs to signal event consumption using - * perf_mmap__write_tail(). Using perf_evlist__mmap_read() does this + * perf_mmap__write_tail(). Using evlist__mmap_read() does this * automatically. * * Similarly, if @auxtrace_overwrite is %false the user needs to signal data @@ -987,7 +885,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, * * Return: %0 on success, negative error code otherwise. */ -int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, +int evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level) @@ -1004,36 +902,36 @@ int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, .comp_level = comp_level }; if (!evlist->mmap) - evlist->mmap = perf_evlist__alloc_mmap(evlist, false); + evlist->mmap = evlist__alloc_mmap(evlist, false); if (!evlist->mmap) return -ENOMEM; - if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) + if (evlist->core.pollfd.entries == NULL && perf_evlist__alloc_pollfd(&evlist->core) < 0) return -ENOMEM; - evlist->mmap_len = perf_evlist__mmap_size(pages); - pr_debug("mmap size %zuB\n", evlist->mmap_len); - mp.mask = evlist->mmap_len - page_size - 1; + evlist->core.mmap_len = evlist__mmap_size(pages); + pr_debug("mmap size %zuB\n", evlist->core.mmap_len); + mp.mask = evlist->core.mmap_len - page_size - 1; - auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->mmap_len, + auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len, auxtrace_pages, auxtrace_overwrite); evlist__for_each_entry(evlist, evsel) { if ((evsel->core.attr.read_format & PERF_FORMAT_ID) && - evsel->sample_id == NULL && - perf_evsel__alloc_id(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0) + evsel->core.sample_id == NULL && + perf_evsel__alloc_id(&evsel->core, perf_cpu_map__nr(cpus), threads->nr) < 0) return -ENOMEM; } if (perf_cpu_map__empty(cpus)) - return perf_evlist__mmap_per_thread(evlist, &mp); + return evlist__mmap_per_thread(evlist, &mp); - return perf_evlist__mmap_per_cpu(evlist, &mp); + return evlist__mmap_per_cpu(evlist, &mp); } -int perf_evlist__mmap(struct evlist *evlist, unsigned int pages) +int evlist__mmap(struct evlist *evlist, unsigned int pages) { - return perf_evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0); + return evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0); } int perf_evlist__create_maps(struct evlist *evlist, struct target *target) @@ -1225,7 +1123,7 @@ u64 perf_evlist__combined_branch_type(struct evlist *evlist) bool perf_evlist__valid_read_format(struct evlist *evlist) { - struct evsel *first = perf_evlist__first(evlist), *pos = first; + struct evsel *first = evlist__first(evlist), *pos = first; u64 read_format = first->core.attr.read_format; u64 sample_type = first->core.attr.sample_type; @@ -1243,15 +1141,9 @@ bool perf_evlist__valid_read_format(struct evlist *evlist) return true; } -u64 perf_evlist__read_format(struct evlist *evlist) -{ - struct evsel *first = perf_evlist__first(evlist); - return first->core.attr.read_format; -} - u16 perf_evlist__id_hdr_size(struct evlist *evlist) { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); struct perf_sample *data; u64 sample_type; u16 size = 0; @@ -1284,7 +1176,7 @@ out: bool perf_evlist__valid_sample_id_all(struct evlist *evlist) { - struct evsel *first = perf_evlist__first(evlist), *pos = first; + struct evsel *first = evlist__first(evlist), *pos = first; evlist__for_each_entry_continue(evlist, pos) { if (first->core.attr.sample_id_all != pos->core.attr.sample_id_all) @@ -1296,7 +1188,7 @@ bool perf_evlist__valid_sample_id_all(struct evlist *evlist) bool perf_evlist__sample_id_all(struct evlist *evlist) { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); return first->core.attr.sample_id_all; } @@ -1529,19 +1421,6 @@ int perf_evlist__parse_sample_timestamp(struct evlist *evlist, return perf_evsel__parse_sample_timestamp(evsel, event, timestamp); } -size_t perf_evlist__fprintf(struct evlist *evlist, FILE *fp) -{ - struct evsel *evsel; - size_t printed = 0; - - evlist__for_each_entry(evlist, evsel) { - printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", - perf_evsel__name(evsel)); - } - - return printed + fprintf(fp, "\n"); -} - int perf_evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size) { @@ -1571,7 +1450,7 @@ int perf_evlist__strerror_open(struct evlist *evlist, "Hint:\tThe current value is %d.", value); break; case EINVAL: { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); int max_freq; if (sysctl__read_int("kernel/perf_event_max_sample_rate", &max_freq) < 0) @@ -1599,7 +1478,7 @@ out_default: int perf_evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size) { char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf)); - int pages_attempted = evlist->mmap_len / 1024, pages_max_per_user, printed = 0; + int pages_attempted = evlist->core.mmap_len / 1024, pages_max_per_user, printed = 0; switch (err) { case EPERM: @@ -1633,7 +1512,7 @@ void perf_evlist__to_front(struct evlist *evlist, struct evsel *evsel, *n; LIST_HEAD(move); - if (move_evsel == perf_evlist__first(evlist)) + if (move_evsel == evlist__first(evlist)) return; evlist__for_each_entry_safe(evlist, n, evsel) { @@ -1754,7 +1633,7 @@ bool perf_evlist__exclude_kernel(struct evlist *evlist) void perf_evlist__force_leader(struct evlist *evlist) { if (!evlist->nr_groups) { - struct evsel *leader = perf_evlist__first(evlist); + struct evsel *leader = evlist__first(evlist); perf_evlist__set_leader(evlist); leader->forced_leader = true; @@ -1780,7 +1659,7 @@ struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list, is_open = false; if (c2->leader == leader) { if (is_open) - evsel__close(c2); + perf_evsel__close(&evsel->core); c2->leader = c2; c2->core.nr_members = 0; } @@ -1844,10 +1723,10 @@ static void *perf_evlist__poll_thread(void *arg) draining = true; if (!draining) - perf_evlist__poll(evlist, 1000); + evlist__poll(evlist, 1000); - for (i = 0; i < evlist->nr_mmaps; i++) { - struct perf_mmap *map = &evlist->mmap[i]; + for (i = 0; i < evlist->core.nr_mmaps; i++) { + struct mmap *map = &evlist->mmap[i]; union perf_event *event; if (perf_mmap__read_init(map)) @@ -1889,7 +1768,7 @@ int perf_evlist__start_sb_thread(struct evlist *evlist, goto out_delete_evlist; } - if (perf_evlist__mmap(evlist, UINT_MAX)) + if (evlist__mmap(evlist, UINT_MAX)) goto out_delete_evlist; evlist__for_each_entry(evlist, counter) { diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a55f0f2546e5..7cfe75522ba5 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -7,11 +7,11 @@ #include <linux/refcount.h> #include <linux/list.h> #include <api/fd/array.h> -#include <stdio.h> #include <internal/evlist.h> +#include <internal/evsel.h> #include "events_stats.h" #include "evsel.h" -#include "mmap.h" +#include <pthread.h> #include <signal.h> #include <unistd.h> @@ -20,16 +20,38 @@ struct thread_map; struct perf_cpu_map; struct record_opts; -#define PERF_EVLIST__HLIST_BITS 8 -#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) +/* + * State machine of bkw_mmap_state: + * + * .________________(forbid)_____________. + * | V + * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY + * ^ ^ | ^ | + * | |__(forbid)____/ |___(forbid)___/| + * | | + * \_________________(3)_______________/ + * + * NOTREADY : Backward ring buffers are not ready + * RUNNING : Backward ring buffers are recording + * DATA_PENDING : We are required to collect data from backward ring buffers + * EMPTY : We have collected data from backward ring buffers. + * + * (0): Setup backward ring buffer + * (1): Pause ring buffers for reading + * (2): Read from ring buffers + * (3): Resume ring buffers for recording + */ +enum bkw_mmap_state { + BKW_MMAP_NOTREADY, + BKW_MMAP_RUNNING, + BKW_MMAP_DATA_PENDING, + BKW_MMAP_EMPTY, +}; struct evlist { struct perf_evlist core; - struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; int nr_groups; - int nr_mmaps; bool enabled; - size_t mmap_len; int id_pos; int is_pos; u64 combined_sample_type; @@ -38,9 +60,8 @@ struct evlist { int cork_fd; pid_t pid; } workload; - struct fdarray pollfd; - struct perf_mmap *mmap; - struct perf_mmap *overwrite_mmap; + struct mmap *mmap; + struct mmap *overwrite_mmap; struct evsel *selected; struct events_stats stats; struct perf_env *env; @@ -65,7 +86,7 @@ struct evlist *perf_evlist__new_default(void); struct evlist *perf_evlist__new_dummy(void); void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, struct perf_thread_map *threads); -void perf_evlist__exit(struct evlist *evlist); +void evlist__exit(struct evlist *evlist); void evlist__delete(struct evlist *evlist); void evlist__add(struct evlist *evlist, struct evsel *entry); @@ -119,17 +140,10 @@ struct evsel * perf_evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name); -void perf_evlist__id_add(struct evlist *evlist, struct evsel *evsel, - int cpu, int thread, u64 id); -int perf_evlist__id_add_fd(struct evlist *evlist, - struct evsel *evsel, - int cpu, int thread, int fd); - -int perf_evlist__add_pollfd(struct evlist *evlist, int fd); -int perf_evlist__alloc_pollfd(struct evlist *evlist); -int perf_evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask); +int evlist__add_pollfd(struct evlist *evlist, int fd); +int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask); -int perf_evlist__poll(struct evlist *evlist, int timeout); +int evlist__poll(struct evlist *evlist, int timeout); struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id); struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist, @@ -139,7 +153,7 @@ struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id); void perf_evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state); -void perf_evlist__mmap_consume(struct evlist *evlist, int idx); +void evlist__mmap_consume(struct evlist *evlist, int idx); int evlist__open(struct evlist *evlist); void evlist__close(struct evlist *evlist); @@ -170,14 +184,14 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, unsigned long perf_event_mlock_kb_in_pages(void); -int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, +int evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level); -int perf_evlist__mmap(struct evlist *evlist, unsigned int pages); -void perf_evlist__munmap(struct evlist *evlist); +int evlist__mmap(struct evlist *evlist, unsigned int pages); +void evlist__munmap(struct evlist *evlist); -size_t perf_evlist__mmap_size(unsigned long pages); +size_t evlist__mmap_size(unsigned long pages); void evlist__disable(struct evlist *evlist); void evlist__enable(struct evlist *evlist); @@ -195,7 +209,6 @@ int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel); void __perf_evlist__set_leader(struct list_head *list); void perf_evlist__set_leader(struct evlist *evlist); -u64 perf_evlist__read_format(struct evlist *evlist); u64 __perf_evlist__combined_sample_type(struct evlist *evlist); u64 perf_evlist__combined_sample_type(struct evlist *evlist); u64 perf_evlist__combined_branch_type(struct evlist *evlist); @@ -221,17 +234,19 @@ static inline bool perf_evlist__empty(struct evlist *evlist) return list_empty(&evlist->core.entries); } -static inline struct evsel *perf_evlist__first(struct evlist *evlist) +static inline struct evsel *evlist__first(struct evlist *evlist) { - return list_entry(evlist->core.entries.next, struct evsel, core.node); + struct perf_evsel *evsel = perf_evlist__first(&evlist->core); + + return container_of(evsel, struct evsel, core); } -static inline struct evsel *perf_evlist__last(struct evlist *evlist) +static inline struct evsel *evlist__last(struct evlist *evlist) { - return list_entry(evlist->core.entries.prev, struct evsel, core.node); -} + struct perf_evsel *evsel = perf_evlist__last(&evlist->core); -size_t perf_evlist__fprintf(struct evlist *evlist, FILE *fp); + return container_of(evsel, struct evsel, core); +} int perf_evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size); int perf_evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 85825384f9e8..5591af81a070 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -30,8 +30,10 @@ #include "counts.h" #include "event.h" #include "evsel.h" +#include "util/evsel_config.h" +#include "util/evsel_fprintf.h" #include "evlist.h" -#include "cpumap.h" +#include <perf/cpumap.h> #include "thread_map.h" #include "target.h" #include "perf_regs.h" @@ -45,6 +47,7 @@ #include "../perf-sys.h" #include "util/parse-branch-options.h" #include <internal/xyarray.h> +#include <internal/lib.h> #include <linux/ctype.h> @@ -1226,36 +1229,6 @@ int evsel__disable(struct evsel *evsel) return err; } -int perf_evsel__alloc_id(struct evsel *evsel, int ncpus, int nthreads) -{ - if (ncpus == 0 || nthreads == 0) - return 0; - - if (evsel->system_wide) - nthreads = 1; - - evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); - if (evsel->sample_id == NULL) - return -ENOMEM; - - evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); - if (evsel->id == NULL) { - xyarray__delete(evsel->sample_id); - evsel->sample_id = NULL; - return -ENOMEM; - } - - return 0; -} - -static void perf_evsel__free_id(struct evsel *evsel) -{ - xyarray__delete(evsel->sample_id); - evsel->sample_id = NULL; - zfree(&evsel->id); - evsel->ids = 0; -} - static void perf_evsel__free_config_terms(struct evsel *evsel) { struct perf_evsel_config_term *term, *h; @@ -1272,7 +1245,7 @@ void perf_evsel__exit(struct evsel *evsel) assert(evsel->evlist == NULL); perf_evsel__free_counts(evsel); perf_evsel__free_fd(&evsel->core); - perf_evsel__free_id(evsel); + perf_evsel__free_id(&evsel->core); perf_evsel__free_config_terms(evsel); cgroup__put(evsel->cgrp); perf_cpu_map__put(evsel->core.cpus); @@ -1472,152 +1445,6 @@ static int get_group_fd(struct evsel *evsel, int cpu, int thread) return fd; } -struct bit_names { - int bit; - const char *name; -}; - -static void __p_bits(char *buf, size_t size, u64 value, struct bit_names *bits) -{ - bool first_bit = true; - int i = 0; - - do { - if (value & bits[i].bit) { - buf += scnprintf(buf, size, "%s%s", first_bit ? "" : "|", bits[i].name); - first_bit = false; - } - } while (bits[++i].name != NULL); -} - -static void __p_sample_type(char *buf, size_t size, u64 value) -{ -#define bit_name(n) { PERF_SAMPLE_##n, #n } - struct bit_names bits[] = { - bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), - bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), - bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), - bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), - bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), - bit_name(WEIGHT), bit_name(PHYS_ADDR), - { .name = NULL, } - }; -#undef bit_name - __p_bits(buf, size, value, bits); -} - -static void __p_branch_sample_type(char *buf, size_t size, u64 value) -{ -#define bit_name(n) { PERF_SAMPLE_BRANCH_##n, #n } - struct bit_names bits[] = { - bit_name(USER), bit_name(KERNEL), bit_name(HV), bit_name(ANY), - bit_name(ANY_CALL), bit_name(ANY_RETURN), bit_name(IND_CALL), - bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX), - bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), - bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), - { .name = NULL, } - }; -#undef bit_name - __p_bits(buf, size, value, bits); -} - -static void __p_read_format(char *buf, size_t size, u64 value) -{ -#define bit_name(n) { PERF_FORMAT_##n, #n } - struct bit_names bits[] = { - bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), - bit_name(ID), bit_name(GROUP), - { .name = NULL, } - }; -#undef bit_name - __p_bits(buf, size, value, bits); -} - -#define BUF_SIZE 1024 - -#define p_hex(val) snprintf(buf, BUF_SIZE, "%#"PRIx64, (uint64_t)(val)) -#define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) -#define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) -#define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) -#define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) -#define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) - -#define PRINT_ATTRn(_n, _f, _p) \ -do { \ - if (attr->_f) { \ - _p(attr->_f); \ - ret += attr__fprintf(fp, _n, buf, priv);\ - } \ -} while (0) - -#define PRINT_ATTRf(_f, _p) PRINT_ATTRn(#_f, _f, _p) - -int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, - attr__fprintf_f attr__fprintf, void *priv) -{ - char buf[BUF_SIZE]; - int ret = 0; - - PRINT_ATTRf(type, p_unsigned); - PRINT_ATTRf(size, p_unsigned); - PRINT_ATTRf(config, p_hex); - PRINT_ATTRn("{ sample_period, sample_freq }", sample_period, p_unsigned); - PRINT_ATTRf(sample_type, p_sample_type); - PRINT_ATTRf(read_format, p_read_format); - - PRINT_ATTRf(disabled, p_unsigned); - PRINT_ATTRf(inherit, p_unsigned); - PRINT_ATTRf(pinned, p_unsigned); - PRINT_ATTRf(exclusive, p_unsigned); - PRINT_ATTRf(exclude_user, p_unsigned); - PRINT_ATTRf(exclude_kernel, p_unsigned); - PRINT_ATTRf(exclude_hv, p_unsigned); - PRINT_ATTRf(exclude_idle, p_unsigned); - PRINT_ATTRf(mmap, p_unsigned); - PRINT_ATTRf(comm, p_unsigned); - PRINT_ATTRf(freq, p_unsigned); - PRINT_ATTRf(inherit_stat, p_unsigned); - PRINT_ATTRf(enable_on_exec, p_unsigned); - PRINT_ATTRf(task, p_unsigned); - PRINT_ATTRf(watermark, p_unsigned); - PRINT_ATTRf(precise_ip, p_unsigned); - PRINT_ATTRf(mmap_data, p_unsigned); - PRINT_ATTRf(sample_id_all, p_unsigned); - PRINT_ATTRf(exclude_host, p_unsigned); - PRINT_ATTRf(exclude_guest, p_unsigned); - PRINT_ATTRf(exclude_callchain_kernel, p_unsigned); - PRINT_ATTRf(exclude_callchain_user, p_unsigned); - PRINT_ATTRf(mmap2, p_unsigned); - PRINT_ATTRf(comm_exec, p_unsigned); - PRINT_ATTRf(use_clockid, p_unsigned); - PRINT_ATTRf(context_switch, p_unsigned); - PRINT_ATTRf(write_backward, p_unsigned); - PRINT_ATTRf(namespaces, p_unsigned); - PRINT_ATTRf(ksymbol, p_unsigned); - PRINT_ATTRf(bpf_event, p_unsigned); - PRINT_ATTRf(aux_output, p_unsigned); - - PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); - PRINT_ATTRf(bp_type, p_unsigned); - PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); - PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); - PRINT_ATTRf(branch_sample_type, p_branch_sample_type); - PRINT_ATTRf(sample_regs_user, p_hex); - PRINT_ATTRf(sample_stack_user, p_unsigned); - PRINT_ATTRf(clockid, p_signed); - PRINT_ATTRf(sample_regs_intr, p_hex); - PRINT_ATTRf(aux_watermark, p_unsigned); - PRINT_ATTRf(sample_max_stack, p_unsigned); - - return ret; -} - -static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, - void *priv __maybe_unused) -{ - return fprintf(fp, " %-32s %s\n", name, val); -} - static void perf_evsel__remove_fd(struct evsel *pos, int nr_cpus, int nr_threads, int thread_idx) @@ -1662,7 +1489,7 @@ static bool ignore_missing_thread(struct evsel *evsel, return false; /* The system wide setup does not work with threads. */ - if (evsel->system_wide) + if (evsel->core.system_wide) return false; /* The -ESRCH is perf event syscall errno for pid's not found. */ @@ -1688,6 +1515,12 @@ static bool ignore_missing_thread(struct evsel *evsel, return true; } +static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, + void *priv __maybe_unused) +{ + return fprintf(fp, " %-32s %s\n", name, val); +} + static void display_attr(struct perf_event_attr *attr) { if (verbose >= 2) { @@ -1771,7 +1604,7 @@ int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, threads = empty_thread_map; } - if (evsel->system_wide) + if (evsel->core.system_wide) nthreads = 1; else nthreads = threads->nr; @@ -1818,7 +1651,7 @@ retry_sample_id: for (thread = 0; thread < nthreads; thread++) { int fd, group_fd; - if (!evsel->cgrp && !evsel->system_wide) + if (!evsel->cgrp && !evsel->core.system_wide) pid = perf_thread_map__pid(threads, thread); group_fd = get_group_fd(evsel, cpu, thread); @@ -1991,7 +1824,7 @@ out_close: void evsel__close(struct evsel *evsel) { perf_evsel__close(&evsel->core); - perf_evsel__free_id(evsel); + perf_evsel__free_id(&evsel->core); } int perf_evsel__open_per_cpu(struct evsel *evsel, @@ -2419,283 +2252,6 @@ int perf_evsel__parse_sample_timestamp(struct evsel *evsel, return 0; } -size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, - u64 read_format) -{ - size_t sz, result = sizeof(struct perf_record_sample); - - if (type & PERF_SAMPLE_IDENTIFIER) - result += sizeof(u64); - - if (type & PERF_SAMPLE_IP) - result += sizeof(u64); - - if (type & PERF_SAMPLE_TID) - result += sizeof(u64); - - if (type & PERF_SAMPLE_TIME) - result += sizeof(u64); - - if (type & PERF_SAMPLE_ADDR) - result += sizeof(u64); - - if (type & PERF_SAMPLE_ID) - result += sizeof(u64); - - if (type & PERF_SAMPLE_STREAM_ID) - result += sizeof(u64); - - if (type & PERF_SAMPLE_CPU) - result += sizeof(u64); - - if (type & PERF_SAMPLE_PERIOD) - result += sizeof(u64); - - if (type & PERF_SAMPLE_READ) { - result += sizeof(u64); - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - result += sizeof(u64); - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - result += sizeof(u64); - /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ - if (read_format & PERF_FORMAT_GROUP) { - sz = sample->read.group.nr * - sizeof(struct sample_read_value); - result += sz; - } else { - result += sizeof(u64); - } - } - - if (type & PERF_SAMPLE_CALLCHAIN) { - sz = (sample->callchain->nr + 1) * sizeof(u64); - result += sz; - } - - if (type & PERF_SAMPLE_RAW) { - result += sizeof(u32); - result += sample->raw_size; - } - - if (type & PERF_SAMPLE_BRANCH_STACK) { - sz = sample->branch_stack->nr * sizeof(struct branch_entry); - sz += sizeof(u64); - result += sz; - } - - if (type & PERF_SAMPLE_REGS_USER) { - if (sample->user_regs.abi) { - result += sizeof(u64); - sz = hweight64(sample->user_regs.mask) * sizeof(u64); - result += sz; - } else { - result += sizeof(u64); - } - } - - if (type & PERF_SAMPLE_STACK_USER) { - sz = sample->user_stack.size; - result += sizeof(u64); - if (sz) { - result += sz; - result += sizeof(u64); - } - } - - if (type & PERF_SAMPLE_WEIGHT) - result += sizeof(u64); - - if (type & PERF_SAMPLE_DATA_SRC) - result += sizeof(u64); - - if (type & PERF_SAMPLE_TRANSACTION) - result += sizeof(u64); - - if (type & PERF_SAMPLE_REGS_INTR) { - if (sample->intr_regs.abi) { - result += sizeof(u64); - sz = hweight64(sample->intr_regs.mask) * sizeof(u64); - result += sz; - } else { - result += sizeof(u64); - } - } - - if (type & PERF_SAMPLE_PHYS_ADDR) - result += sizeof(u64); - - return result; -} - -int perf_event__synthesize_sample(union perf_event *event, u64 type, - u64 read_format, - const struct perf_sample *sample) -{ - __u64 *array; - size_t sz; - /* - * used for cross-endian analysis. See git commit 65014ab3 - * for why this goofiness is needed. - */ - union u64_swap u; - - array = event->sample.array; - - if (type & PERF_SAMPLE_IDENTIFIER) { - *array = sample->id; - array++; - } - - if (type & PERF_SAMPLE_IP) { - *array = sample->ip; - array++; - } - - if (type & PERF_SAMPLE_TID) { - u.val32[0] = sample->pid; - u.val32[1] = sample->tid; - *array = u.val64; - array++; - } - - if (type & PERF_SAMPLE_TIME) { - *array = sample->time; - array++; - } - - if (type & PERF_SAMPLE_ADDR) { - *array = sample->addr; - array++; - } - - if (type & PERF_SAMPLE_ID) { - *array = sample->id; - array++; - } - - if (type & PERF_SAMPLE_STREAM_ID) { - *array = sample->stream_id; - array++; - } - - if (type & PERF_SAMPLE_CPU) { - u.val32[0] = sample->cpu; - u.val32[1] = 0; - *array = u.val64; - array++; - } - - if (type & PERF_SAMPLE_PERIOD) { - *array = sample->period; - array++; - } - - if (type & PERF_SAMPLE_READ) { - if (read_format & PERF_FORMAT_GROUP) - *array = sample->read.group.nr; - else - *array = sample->read.one.value; - array++; - - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { - *array = sample->read.time_enabled; - array++; - } - - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { - *array = sample->read.time_running; - array++; - } - - /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ - if (read_format & PERF_FORMAT_GROUP) { - sz = sample->read.group.nr * - sizeof(struct sample_read_value); - memcpy(array, sample->read.group.values, sz); - array = (void *)array + sz; - } else { - *array = sample->read.one.id; - array++; - } - } - - if (type & PERF_SAMPLE_CALLCHAIN) { - sz = (sample->callchain->nr + 1) * sizeof(u64); - memcpy(array, sample->callchain, sz); - array = (void *)array + sz; - } - - if (type & PERF_SAMPLE_RAW) { - u.val32[0] = sample->raw_size; - *array = u.val64; - array = (void *)array + sizeof(u32); - - memcpy(array, sample->raw_data, sample->raw_size); - array = (void *)array + sample->raw_size; - } - - if (type & PERF_SAMPLE_BRANCH_STACK) { - sz = sample->branch_stack->nr * sizeof(struct branch_entry); - sz += sizeof(u64); - memcpy(array, sample->branch_stack, sz); - array = (void *)array + sz; - } - - if (type & PERF_SAMPLE_REGS_USER) { - if (sample->user_regs.abi) { - *array++ = sample->user_regs.abi; - sz = hweight64(sample->user_regs.mask) * sizeof(u64); - memcpy(array, sample->user_regs.regs, sz); - array = (void *)array + sz; - } else { - *array++ = 0; - } - } - - if (type & PERF_SAMPLE_STACK_USER) { - sz = sample->user_stack.size; - *array++ = sz; - if (sz) { - memcpy(array, sample->user_stack.data, sz); - array = (void *)array + sz; - *array++ = sz; - } - } - - if (type & PERF_SAMPLE_WEIGHT) { - *array = sample->weight; - array++; - } - - if (type & PERF_SAMPLE_DATA_SRC) { - *array = sample->data_src; - array++; - } - - if (type & PERF_SAMPLE_TRANSACTION) { - *array = sample->transaction; - array++; - } - - if (type & PERF_SAMPLE_REGS_INTR) { - if (sample->intr_regs.abi) { - *array++ = sample->intr_regs.abi; - sz = hweight64(sample->intr_regs.mask) * sizeof(u64); - memcpy(array, sample->intr_regs.regs, sz); - array = (void *)array + sz; - } else { - *array++ = 0; - } - } - - if (type & PERF_SAMPLE_PHYS_ADDR) { - *array = sample->phys_addr; - array++; - } - - return 0; -} - struct tep_format_field *perf_evsel__field(struct evsel *evsel, const char *name) { return tep_find_field(evsel->tp_format, name); @@ -2811,9 +2367,11 @@ bool perf_evsel__fallback(struct evsel *evsel, int err, if (evsel->name) free(evsel->name); evsel->name = new_name; - scnprintf(msg, msgsize, -"kernel.perf_event_paranoid=%d, trying to fall back to excluding kernel samples", paranoid); + scnprintf(msg, msgsize, "kernel.perf_event_paranoid=%d, trying " + "to fall back to excluding kernel and hypervisor " + " samples", paranoid); evsel->core.attr.exclude_kernel = 1; + evsel->core.attr.exclude_hv = 1; return true; } @@ -2966,7 +2524,7 @@ static int store_evsel_ids(struct evsel *evsel, struct evlist *evlist) thread++) { int fd = FD(evsel, cpu, thread); - if (perf_evlist__id_add_fd(evlist, evsel, + if (perf_evlist__id_add_fd(&evlist->core, &evsel->core, cpu, thread, fd) < 0) return -1; } @@ -2980,7 +2538,7 @@ int perf_evsel__store_ids(struct evsel *evsel, struct evlist *evlist) struct perf_cpu_map *cpus = evsel->core.cpus; struct perf_thread_map *threads = evsel->core.threads; - if (perf_evsel__alloc_id(evsel, cpus->nr, threads->nr)) + if (perf_evsel__alloc_id(&evsel->core, cpus->nr, threads->nr)) return -ENOMEM; return store_evsel_ids(evsel, evlist); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 68321d10eb2d..ddc5ee6f6592 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -4,7 +4,6 @@ #include <linux/list.h> #include <stdbool.h> -#include <stdio.h> #include <sys/types.h> #include <linux/perf_event.h> #include <linux/types.h> @@ -13,79 +12,11 @@ #include "symbol_conf.h" #include <internal/cpumap.h> -struct addr_location; -struct evsel; -union perf_event; - -/* - * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are - * more than one entry in the evlist. - */ -struct perf_sample_id { - struct hlist_node node; - u64 id; - struct evsel *evsel; - /* - * 'idx' will be used for AUX area sampling. A sample will have AUX area - * data that will be queued for decoding, where there are separate - * queues for each CPU (per-cpu tracing) or task (per-thread tracing). - * The sample ID can be used to lookup 'idx' which is effectively the - * queue number. - */ - int idx; - int cpu; - pid_t tid; - - /* Holds total ID period value for PERF_SAMPLE_READ processing. */ - u64 period; -}; - +struct bpf_object; struct cgroup; - -/* - * The 'struct perf_evsel_config_term' is used to pass event - * specific configuration data to perf_evsel__config routine. - * It is allocated within event parsing and attached to - * perf_evsel::config_terms list head. -*/ -enum term_type { - PERF_EVSEL__CONFIG_TERM_PERIOD, - PERF_EVSEL__CONFIG_TERM_FREQ, - PERF_EVSEL__CONFIG_TERM_TIME, - PERF_EVSEL__CONFIG_TERM_CALLGRAPH, - PERF_EVSEL__CONFIG_TERM_STACK_USER, - PERF_EVSEL__CONFIG_TERM_INHERIT, - PERF_EVSEL__CONFIG_TERM_MAX_STACK, - PERF_EVSEL__CONFIG_TERM_MAX_EVENTS, - PERF_EVSEL__CONFIG_TERM_OVERWRITE, - PERF_EVSEL__CONFIG_TERM_DRV_CFG, - PERF_EVSEL__CONFIG_TERM_BRANCH, - PERF_EVSEL__CONFIG_TERM_PERCORE, - PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT, -}; - -struct perf_evsel_config_term { - struct list_head list; - enum term_type type; - union { - u64 period; - u64 freq; - bool time; - char *callgraph; - char *drv_cfg; - u64 stack_user; - int max_stack; - bool inherit; - bool overwrite; - char *branch; - unsigned long max_events; - bool percore; - bool aux_output; - } val; - bool weak; -}; - +struct perf_counts; struct perf_stat_evsel; +union perf_event; typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data); @@ -94,10 +25,6 @@ enum perf_tool_event { PERF_TOOL_DURATION_TIME = 1, }; -struct bpf_object; -struct perf_counts; -struct xyarray; - /** struct evsel - event selector * * @evlist - evlist this evsel is in, if it is in one. @@ -117,12 +44,9 @@ struct evsel { struct perf_evsel core; struct evlist *evlist; char *filter; - struct xyarray *sample_id; - u64 *id; struct perf_counts *counts; struct perf_counts *prev_raw_counts; int idx; - u32 ids; unsigned long max_events; unsigned long nr_events_printed; char *name; @@ -146,7 +70,6 @@ struct evsel { bool disabled; bool no_aux_samples; bool immediate; - bool system_wide; bool tracking; bool per_pkg; bool precise_max; @@ -179,11 +102,6 @@ struct evsel { } side_band; }; -union u64_swap { - u64 val64; - u32 val32[2]; -}; - struct perf_missing_features { bool sample_id_all; bool exclude_guest; @@ -282,8 +200,6 @@ const char *perf_evsel__name(struct evsel *evsel); const char *perf_evsel__group_name(struct evsel *evsel); int perf_evsel__group_desc(struct evsel *evsel, char *buf, size_t size); -int perf_evsel__alloc_id(struct evsel *evsel, int ncpus, int nthreads); - void __perf_evsel__set_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit); void __perf_evsel__reset_sample_bit(struct evsel *evsel, @@ -439,37 +355,6 @@ static inline bool perf_evsel__is_clock(struct evsel *evsel) perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK); } -struct perf_attr_details { - bool freq; - bool verbose; - bool event_group; - bool force; - bool trace_fields; -}; - -int perf_evsel__fprintf(struct evsel *evsel, - struct perf_attr_details *details, FILE *fp); - -#define EVSEL__PRINT_IP (1<<0) -#define EVSEL__PRINT_SYM (1<<1) -#define EVSEL__PRINT_DSO (1<<2) -#define EVSEL__PRINT_SYMOFFSET (1<<3) -#define EVSEL__PRINT_ONELINE (1<<4) -#define EVSEL__PRINT_SRCLINE (1<<5) -#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) -#define EVSEL__PRINT_CALLCHAIN_ARROW (1<<7) -#define EVSEL__PRINT_SKIP_IGNORED (1<<8) - -struct callchain_cursor; - -int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, - unsigned int print_opts, - struct callchain_cursor *cursor, FILE *fp); - -int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, - int left_alignment, unsigned int print_opts, - struct callchain_cursor *cursor, FILE *fp); - bool perf_evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize); int perf_evsel__open_strerror(struct evsel *evsel, struct target *target, @@ -502,11 +387,6 @@ static inline bool evsel__has_callchain(const struct evsel *evsel) return (evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; } -typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); - -int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, - attr__fprintf_f attr__fprintf, void *priv); - struct perf_env *perf_evsel__env(struct evsel *evsel); int perf_evsel__store_ids(struct evsel *evsel, struct evlist *evlist); diff --git a/tools/perf/util/evsel_config.h b/tools/perf/util/evsel_config.h new file mode 100644 index 000000000000..8a7648037c18 --- /dev/null +++ b/tools/perf/util/evsel_config.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __PERF_EVSEL_CONFIG_H +#define __PERF_EVSEL_CONFIG_H 1 + +#include <linux/types.h> +#include <stdbool.h> + +/* + * The 'struct perf_evsel_config_term' is used to pass event + * specific configuration data to perf_evsel__config routine. + * It is allocated within event parsing and attached to + * perf_evsel::config_terms list head. +*/ +enum evsel_term_type { + PERF_EVSEL__CONFIG_TERM_PERIOD, + PERF_EVSEL__CONFIG_TERM_FREQ, + PERF_EVSEL__CONFIG_TERM_TIME, + PERF_EVSEL__CONFIG_TERM_CALLGRAPH, + PERF_EVSEL__CONFIG_TERM_STACK_USER, + PERF_EVSEL__CONFIG_TERM_INHERIT, + PERF_EVSEL__CONFIG_TERM_MAX_STACK, + PERF_EVSEL__CONFIG_TERM_MAX_EVENTS, + PERF_EVSEL__CONFIG_TERM_OVERWRITE, + PERF_EVSEL__CONFIG_TERM_DRV_CFG, + PERF_EVSEL__CONFIG_TERM_BRANCH, + PERF_EVSEL__CONFIG_TERM_PERCORE, + PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT, +}; + +struct perf_evsel_config_term { + struct list_head list; + enum evsel_term_type type; + union { + u64 period; + u64 freq; + bool time; + char *callgraph; + char *drv_cfg; + u64 stack_user; + int max_stack; + bool inherit; + bool overwrite; + char *branch; + unsigned long max_events; + bool percore; + bool aux_output; + } val; + bool weak; +}; +#endif // __PERF_EVSEL_CONFIG_H diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 496fec01f5d1..028df7afb0dc 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -4,6 +4,8 @@ #include <stdbool.h> #include <traceevent/event-parse.h> #include "evsel.h" +#include "util/evsel_fprintf.h" +#include "util/event.h" #include "callchain.h" #include "map.h" #include "strlist.h" @@ -101,7 +103,7 @@ out: int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, unsigned int print_opts, struct callchain_cursor *cursor, - FILE *fp) + struct strlist *bt_stop_list, FILE *fp) { int printed = 0; struct callchain_cursor_node *node; @@ -174,10 +176,8 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, printed += fprintf(fp, "\n"); /* Add srccode here too? */ - if (symbol_conf.bt_stop_list && - node->sym && - strlist__has_entry(symbol_conf.bt_stop_list, - node->sym->name)) { + if (bt_stop_list && node->sym && + strlist__has_entry(bt_stop_list, node->sym->name)) { break; } @@ -192,7 +192,7 @@ next: int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, int left_alignment, unsigned int print_opts, - struct callchain_cursor *cursor, FILE *fp) + struct callchain_cursor *cursor, struct strlist *bt_stop_list, FILE *fp) { int printed = 0; int print_ip = print_opts & EVSEL__PRINT_IP; @@ -203,8 +203,8 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; if (cursor != NULL) { - printed += sample__fprintf_callchain(sample, left_alignment, - print_opts, cursor, fp); + printed += sample__fprintf_callchain(sample, left_alignment, print_opts, + cursor, bt_stop_list, fp); } else { printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); diff --git a/tools/perf/util/evsel_fprintf.h b/tools/perf/util/evsel_fprintf.h new file mode 100644 index 000000000000..47e6c8456bb1 --- /dev/null +++ b/tools/perf/util/evsel_fprintf.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef __PERF_EVSEL_FPRINTF_H +#define __PERF_EVSEL_FPRINTF_H 1 + +#include <stdio.h> +#include <stdbool.h> + +struct evsel; + +struct perf_attr_details { + bool freq; + bool verbose; + bool event_group; + bool force; + bool trace_fields; +}; + +int perf_evsel__fprintf(struct evsel *evsel, + struct perf_attr_details *details, FILE *fp); + +#define EVSEL__PRINT_IP (1<<0) +#define EVSEL__PRINT_SYM (1<<1) +#define EVSEL__PRINT_DSO (1<<2) +#define EVSEL__PRINT_SYMOFFSET (1<<3) +#define EVSEL__PRINT_ONELINE (1<<4) +#define EVSEL__PRINT_SRCLINE (1<<5) +#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) +#define EVSEL__PRINT_CALLCHAIN_ARROW (1<<7) +#define EVSEL__PRINT_SKIP_IGNORED (1<<8) + +struct addr_location; +struct perf_event_attr; +struct perf_sample; +struct callchain_cursor; +struct strlist; + +int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, + unsigned int print_opts, struct callchain_cursor *cursor, + struct strlist *bt_stop_list, FILE *fp); + +int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, + int left_alignment, unsigned int print_opts, + struct callchain_cursor *cursor, + struct strlist *bt_stop_list, FILE *fp); + +typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); + +int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, + attr__fprintf_f attr__fprintf, void *priv); +#endif // __PERF_EVSEL_H diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h index b72440bf9a79..d4137559be05 100644 --- a/tools/perf/util/genelf.h +++ b/tools/perf/util/genelf.h @@ -35,6 +35,9 @@ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_ent #elif defined(__sparc__) #define GEN_ELF_ARCH EM_SPARC #define GEN_ELF_CLASS ELFCLASS32 +#elif defined(__s390x__) +#define GEN_ELF_ARCH EM_S390 +#define GEN_ELF_CLASS ELFCLASS64 #else #error "unsupported architecture" #endif diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b0c34dda30a0..86d9396cb131 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -25,6 +25,7 @@ #include "dso.h" #include "evlist.h" #include "evsel.h" +#include "util/evsel_fprintf.h" #include "header.h" #include "memswap.h" #include "trace-event.h" @@ -42,11 +43,12 @@ #include "tool.h" #include "time-utils.h" #include "units.h" -#include "util.h" +#include "util/util.h" // perf_exe() #include "cputopo.h" #include "bpf-event.h" #include <linux/ctype.h> +#include <internal/lib.h> /* * magic2 = "PERFILE2" @@ -70,15 +72,6 @@ struct perf_file_attr { struct perf_file_section ids; }; -struct feat_fd { - struct perf_header *ph; - int fd; - void *buf; /* Either buf != NULL or fd >= 0 */ - ssize_t offset; - size_t size; - struct evsel *events; -}; - void perf_header__set_feat(struct perf_header *header, int feat) { set_bit(feat, header->adds_features); @@ -524,7 +517,7 @@ static int write_event_desc(struct feat_fd *ff, * copy into an nri to be independent of the * type of ids, */ - nri = evsel->ids; + nri = evsel->core.ids; ret = do_write(ff, &nri, sizeof(nri)); if (ret < 0) return ret; @@ -538,7 +531,7 @@ static int write_event_desc(struct feat_fd *ff, /* * write unique ids for this event */ - ret = do_write(ff, evsel->id, evsel->ids * sizeof(u64)); + ret = do_write(ff, evsel->core.id, evsel->core.ids * sizeof(u64)); if (ret < 0) return ret; } @@ -1081,7 +1074,7 @@ static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 lev scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); if (sysfs__read_str(file, &cache->map, &len)) { - zfree(&cache->map); + zfree(&cache->size); zfree(&cache->type); return -1; } @@ -1598,7 +1591,7 @@ static void free_event_desc(struct evsel *events) for (evsel = events; evsel->core.attr.size; evsel++) { zfree(&evsel->name); - zfree(&evsel->id); + zfree(&evsel->core.id); } free(events); @@ -1664,8 +1657,8 @@ static struct evsel *read_event_desc(struct feat_fd *ff) id = calloc(nr, sizeof(*id)); if (!id) goto error; - evsel->ids = nr; - evsel->id = id; + evsel->core.ids = nr; + evsel->core.id = id; for (j = 0 ; j < nr; j++) { if (do_read_u64(ff, id)) @@ -1707,9 +1700,9 @@ static void print_event_desc(struct feat_fd *ff, FILE *fp) for (evsel = events; evsel->core.attr.size; evsel++) { fprintf(fp, "# event : name = %s, ", evsel->name); - if (evsel->ids) { + if (evsel->core.ids) { fprintf(fp, ", id = {"); - for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { + for (j = 0, id = evsel->core.id; j < evsel->core.ids; j++, id++) { if (j) fputc(',', fp); fprintf(fp, " %"PRIu64, *id); @@ -2823,15 +2816,6 @@ static int process_compressed(struct feat_fd *ff, return 0; } -struct feature_ops { - int (*write)(struct feat_fd *ff, struct evlist *evlist); - void (*print)(struct feat_fd *ff, FILE *fp); - int (*process)(struct feat_fd *ff, void *data); - const char *name; - bool full_only; - bool synthesize; -}; - #define FEAT_OPR(n, func, __full_only) \ [HEADER_##n] = { \ .name = __stringify(n), \ @@ -2858,8 +2842,10 @@ struct feature_ops { #define process_branch_stack NULL #define process_stat NULL +// Only used in util/synthetic-events.c +const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; -static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { +const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPN(TRACING_DATA, tracing_data, false), FEAT_OPN(BUILD_ID, build_id, false), FEAT_OPR(HOSTNAME, hostname, false), @@ -3083,7 +3069,7 @@ int perf_session__write_header(struct perf_session *session, evlist__for_each_entry(session->evlist, evsel) { evsel->id_offset = lseek(fd, 0, SEEK_CUR); - err = do_write(&ff, evsel->id, evsel->ids * sizeof(u64)); + err = do_write(&ff, evsel->core.id, evsel->core.ids * sizeof(u64)); if (err < 0) { pr_debug("failed to write perf header\n"); return err; @@ -3097,7 +3083,7 @@ int perf_session__write_header(struct perf_session *session, .attr = evsel->core.attr, .ids = { .offset = evsel->id_offset, - .size = evsel->ids * sizeof(u64), + .size = evsel->core.ids * sizeof(u64), } }; err = do_write(&ff, &f_attr, sizeof(f_attr)); @@ -3624,7 +3610,7 @@ int perf_session__read_header(struct perf_session *session) * for allocating the perf_sample_id table we fake 1 cpu and * hattr->ids threads. */ - if (perf_evsel__alloc_id(evsel, 1, nr_ids)) + if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids)) goto out_delete_evlist; lseek(fd, f_attr.ids.offset, SEEK_SET); @@ -3633,7 +3619,7 @@ int perf_session__read_header(struct perf_session *session) if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) goto out_errno; - perf_evlist__id_add(session->evlist, evsel, 0, j, f_id); + perf_evlist__id_add(&session->evlist->core, &evsel->core, 0, j, f_id); } lseek(fd, tmp, SEEK_SET); @@ -3656,105 +3642,6 @@ out_delete_evlist: return -ENOMEM; } -int perf_event__synthesize_attr(struct perf_tool *tool, - struct perf_event_attr *attr, u32 ids, u64 *id, - perf_event__handler_t process) -{ - union perf_event *ev; - size_t size; - int err; - - size = sizeof(struct perf_event_attr); - size = PERF_ALIGN(size, sizeof(u64)); - size += sizeof(struct perf_event_header); - size += ids * sizeof(u64); - - ev = zalloc(size); - - if (ev == NULL) - return -ENOMEM; - - ev->attr.attr = *attr; - memcpy(ev->attr.id, id, ids * sizeof(u64)); - - ev->attr.header.type = PERF_RECORD_HEADER_ATTR; - ev->attr.header.size = (u16)size; - - if (ev->attr.header.size == size) - err = process(tool, ev, NULL, NULL); - else - err = -E2BIG; - - free(ev); - - return err; -} - -int perf_event__synthesize_features(struct perf_tool *tool, - struct perf_session *session, - struct evlist *evlist, - perf_event__handler_t process) -{ - struct perf_header *header = &session->header; - struct feat_fd ff; - struct perf_record_header_feature *fe; - size_t sz, sz_hdr; - int feat, ret; - - sz_hdr = sizeof(fe->header); - sz = sizeof(union perf_event); - /* get a nice alignment */ - sz = PERF_ALIGN(sz, page_size); - - memset(&ff, 0, sizeof(ff)); - - ff.buf = malloc(sz); - if (!ff.buf) - return -ENOMEM; - - ff.size = sz - sz_hdr; - ff.ph = &session->header; - - for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { - if (!feat_ops[feat].synthesize) { - pr_debug("No record header feature for header :%d\n", feat); - continue; - } - - ff.offset = sizeof(*fe); - - ret = feat_ops[feat].write(&ff, evlist); - if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { - pr_debug("Error writing feature\n"); - continue; - } - /* ff.buf may have changed due to realloc in do_write() */ - fe = ff.buf; - memset(fe, 0, sizeof(*fe)); - - fe->feat_id = feat; - fe->header.type = PERF_RECORD_HEADER_FEATURE; - fe->header.size = ff.offset; - - ret = process(tool, ff.buf, NULL, NULL); - if (ret) { - free(ff.buf); - return ret; - } - } - - /* Send HEADER_LAST_FEATURE mark. */ - fe = ff.buf; - fe->feat_id = HEADER_LAST_FEATURE; - fe->header.type = PERF_RECORD_HEADER_FEATURE; - fe->header.size = sizeof(*fe); - - ret = process(tool, ff.buf, NULL, NULL); - - free(ff.buf); - return ret; -} - int perf_event__process_feature(struct perf_session *session, union perf_event *event) { @@ -3797,113 +3684,6 @@ int perf_event__process_feature(struct perf_session *session, return 0; } -static struct perf_record_event_update * -event_update_event__new(size_t size, u64 type, u64 id) -{ - struct perf_record_event_update *ev; - - size += sizeof(*ev); - size = PERF_ALIGN(size, sizeof(u64)); - - ev = zalloc(size); - if (ev) { - ev->header.type = PERF_RECORD_EVENT_UPDATE; - ev->header.size = (u16)size; - ev->type = type; - ev->id = id; - } - return ev; -} - -int -perf_event__synthesize_event_update_unit(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process) -{ - struct perf_record_event_update *ev; - size_t size = strlen(evsel->unit); - int err; - - ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]); - if (ev == NULL) - return -ENOMEM; - - strlcpy(ev->data, evsel->unit, size + 1); - err = process(tool, (union perf_event *)ev, NULL, NULL); - free(ev); - return err; -} - -int -perf_event__synthesize_event_update_scale(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process) -{ - struct perf_record_event_update *ev; - struct perf_record_event_update_scale *ev_data; - int err; - - ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]); - if (ev == NULL) - return -ENOMEM; - - ev_data = (struct perf_record_event_update_scale *)ev->data; - ev_data->scale = evsel->scale; - err = process(tool, (union perf_event*) ev, NULL, NULL); - free(ev); - return err; -} - -int -perf_event__synthesize_event_update_name(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process) -{ - struct perf_record_event_update *ev; - size_t len = strlen(evsel->name); - int err; - - ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]); - if (ev == NULL) - return -ENOMEM; - - strlcpy(ev->data, evsel->name, len + 1); - err = process(tool, (union perf_event*) ev, NULL, NULL); - free(ev); - return err; -} - -int -perf_event__synthesize_event_update_cpus(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process) -{ - size_t size = sizeof(struct perf_record_event_update); - struct perf_record_event_update *ev; - int max, err; - u16 type; - - if (!evsel->core.own_cpus) - return 0; - - ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); - if (!ev) - return -ENOMEM; - - ev->header.type = PERF_RECORD_EVENT_UPDATE; - ev->header.size = (u16)size; - ev->type = PERF_EVENT_UPDATE__CPUS; - ev->id = evsel->id[0]; - - cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, - evsel->core.own_cpus, - type, max); - - err = process(tool, (union perf_event*) ev, NULL, NULL); - free(ev); - return err; -} - size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) { struct perf_record_event_update *ev = &event->event_update; @@ -3943,93 +3723,6 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) return ret; } -int perf_event__synthesize_attrs(struct perf_tool *tool, - struct evlist *evlist, - perf_event__handler_t process) -{ - struct evsel *evsel; - int err = 0; - - evlist__for_each_entry(evlist, evsel) { - err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->ids, - evsel->id, process); - if (err) { - pr_debug("failed to create perf header attribute\n"); - return err; - } - } - - return err; -} - -static bool has_unit(struct evsel *counter) -{ - return counter->unit && *counter->unit; -} - -static bool has_scale(struct evsel *counter) -{ - return counter->scale != 1; -} - -int perf_event__synthesize_extra_attr(struct perf_tool *tool, - struct evlist *evsel_list, - perf_event__handler_t process, - bool is_pipe) -{ - struct evsel *counter; - int err; - - /* - * Synthesize other events stuff not carried within - * attr event - unit, scale, name - */ - evlist__for_each_entry(evsel_list, counter) { - if (!counter->supported) - continue; - - /* - * Synthesize unit and scale only if it's defined. - */ - if (has_unit(counter)) { - err = perf_event__synthesize_event_update_unit(tool, counter, process); - if (err < 0) { - pr_err("Couldn't synthesize evsel unit.\n"); - return err; - } - } - - if (has_scale(counter)) { - err = perf_event__synthesize_event_update_scale(tool, counter, process); - if (err < 0) { - pr_err("Couldn't synthesize evsel counter.\n"); - return err; - } - } - - if (counter->core.own_cpus) { - err = perf_event__synthesize_event_update_cpus(tool, counter, process); - if (err < 0) { - pr_err("Couldn't synthesize evsel cpus.\n"); - return err; - } - } - - /* - * Name is needed only for pipe output, - * perf.data carries event names. - */ - if (is_pipe) { - err = perf_event__synthesize_event_update_name(tool, counter, process); - if (err < 0) { - pr_err("Couldn't synthesize evsel name.\n"); - return err; - } - } - } - return 0; -} - int perf_event__process_attr(struct perf_tool *tool __maybe_unused, union perf_event *event, struct evlist **pevlist) @@ -4058,11 +3751,11 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, * for allocating the perf_sample_id table we fake 1 cpu and * hattr->ids threads. */ - if (perf_evsel__alloc_id(evsel, 1, n_ids)) + if (perf_evsel__alloc_id(&evsel->core, 1, n_ids)) return -ENOMEM; for (i = 0; i < n_ids; i++) { - perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); + perf_evlist__id_add(&evlist->core, &evsel->core, 0, i, event->attr.id[i]); } return 0; @@ -4114,55 +3807,6 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, return 0; } -int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, - struct evlist *evlist, - perf_event__handler_t process) -{ - union perf_event ev; - struct tracing_data *tdata; - ssize_t size = 0, aligned_size = 0, padding; - struct feat_fd ff; - int err __maybe_unused = 0; - - /* - * We are going to store the size of the data followed - * by the data contents. Since the fd descriptor is a pipe, - * we cannot seek back to store the size of the data once - * we know it. Instead we: - * - * - write the tracing data to the temp file - * - get/write the data size to pipe - * - write the tracing data from the temp file - * to the pipe - */ - tdata = tracing_data_get(&evlist->core.entries, fd, true); - if (!tdata) - return -1; - - memset(&ev, 0, sizeof(ev)); - - ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; - size = tdata->size; - aligned_size = PERF_ALIGN(size, sizeof(u64)); - padding = aligned_size - size; - ev.tracing_data.header.size = sizeof(ev.tracing_data); - ev.tracing_data.size = aligned_size; - - process(tool, &ev, NULL, NULL); - - /* - * The put function will copy all the tracing data - * stored in temp file to the pipe. - */ - tracing_data_put(tdata); - - ff = (struct feat_fd){ .fd = fd }; - if (write_padded(&ff, NULL, 0, padding)) - return -1; - - return aligned_size; -} - int perf_event__process_tracing_data(struct perf_session *session, union perf_event *event) { @@ -4202,34 +3846,6 @@ int perf_event__process_tracing_data(struct perf_session *session, return size_read + padding; } -int perf_event__synthesize_build_id(struct perf_tool *tool, - struct dso *pos, u16 misc, - perf_event__handler_t process, - struct machine *machine) -{ - union perf_event ev; - size_t len; - int err = 0; - - if (!pos->hit) - return err; - - memset(&ev, 0, sizeof(ev)); - - len = pos->long_name_len + 1; - len = PERF_ALIGN(len, NAME_ALIGN); - memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); - ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; - ev.build_id.header.misc = misc; - ev.build_id.pid = machine->pid; - ev.build_id.header.size = sizeof(ev.build_id) + len; - memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); - - err = process(tool, &ev, NULL, machine); - - return err; -} - int perf_event__process_build_id(struct perf_session *session, union perf_event *event) { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 3e48ae3c49b1..ca53a929e9fd 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -5,10 +5,10 @@ #include <linux/stddef.h> #include <linux/perf_event.h> #include <sys/types.h> +#include <stdio.h> // FILE #include <stdbool.h> #include <linux/bitmap.h> #include <linux/types.h> -#include "event.h" #include "env.h" #include "pmu.h" @@ -92,8 +92,28 @@ struct perf_header { struct perf_env env; }; +struct feat_fd { + struct perf_header *ph; + int fd; + void *buf; /* Either buf != NULL or fd >= 0 */ + ssize_t offset; + size_t size; + struct evsel *events; +}; + +struct perf_header_feature_ops { + int (*write)(struct feat_fd *ff, struct evlist *evlist); + void (*print)(struct feat_fd *ff, FILE *fp); + int (*process)(struct feat_fd *ff, void *data); + const char *name; + bool full_only; + bool synthesize; +}; + struct evlist; struct perf_session; +struct perf_tool; +union perf_event; int perf_session__read_header(struct perf_session *session); int perf_session__write_header(struct perf_session *session, @@ -115,54 +135,16 @@ int perf_header__process_sections(struct perf_header *header, int fd, int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); -int perf_event__synthesize_features(struct perf_tool *tool, - struct perf_session *session, - struct evlist *evlist, - perf_event__handler_t process); - -int perf_event__synthesize_extra_attr(struct perf_tool *tool, - struct evlist *evsel_list, - perf_event__handler_t process, - bool is_pipe); - int perf_event__process_feature(struct perf_session *session, union perf_event *event); - -int perf_event__synthesize_attr(struct perf_tool *tool, - struct perf_event_attr *attr, u32 ids, u64 *id, - perf_event__handler_t process); -int perf_event__synthesize_attrs(struct perf_tool *tool, - struct evlist *evlist, - perf_event__handler_t process); -int perf_event__synthesize_event_update_unit(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process); -int perf_event__synthesize_event_update_scale(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process); -int perf_event__synthesize_event_update_name(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process); -int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, - struct evsel *evsel, - perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, struct evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool, union perf_event *event, struct evlist **pevlist); size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp); - -int perf_event__synthesize_tracing_data(struct perf_tool *tool, - int fd, struct evlist *evlist, - perf_event__handler_t process); int perf_event__process_tracing_data(struct perf_session *session, union perf_event *event); - -int perf_event__synthesize_build_id(struct perf_tool *tool, - struct dso *pos, u16 misc, - perf_event__handler_t process, - struct machine *machine); int perf_event__process_build_id(struct perf_session *session, union perf_event *event); bool is_perf_magic(u64 magic); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 34803e33dc80..6a186b668303 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -15,6 +15,7 @@ struct addr_location; struct map_symbol; struct mem_info; struct branch_info; +struct branch_stack; struct block_info; struct symbol; struct ui_progress; diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index aacffa2b0362..34cb380d19a3 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -14,7 +14,6 @@ #include <linux/log2.h> #include <linux/zalloc.h> -#include "cpumap.h" #include "color.h" #include "evsel.h" #include "evlist.h" @@ -29,6 +28,7 @@ #include "auxtrace.h" #include "intel-pt-decoder/intel-pt-insn-decoder.h" #include "intel-bts.h" +#include "util/synthetic-events.h" #define MAX_TIMESTAMP (~0ULL) @@ -768,7 +768,7 @@ static int intel_bts_synth_events(struct intel_bts *bts, int err; evlist__for_each_entry(evlist, evsel) { - if (evsel->core.attr.type == bts->pmu_type && evsel->ids) { + if (evsel->core.attr.type == bts->pmu_type && evsel->core.ids) { found = true; break; } @@ -795,7 +795,7 @@ static int intel_bts_synth_events(struct intel_bts *bts, attr.sample_id_all = evsel->core.attr.sample_id_all; attr.read_format = evsel->core.attr.read_format; - id = evsel->id[0] + 1000000000; + id = evsel->core.id[0] + 1000000000; if (!id) id = 1; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 9b56fb74bedf..a1c9eb6d4f40 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -33,6 +33,7 @@ #include "tsc.h" #include "intel-pt.h" #include "config.h" +#include "util/synthetic-events.h" #include "time-utils.h" #include "../arch/x86/include/uapi/asm/perf_regs.h" @@ -1704,7 +1705,7 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) struct intel_pt *pt = ptq->pt; struct evsel *evsel = pt->pebs_evsel; u64 sample_type = evsel->core.attr.sample_type; - u64 id = evsel->id[0]; + u64 id = evsel->core.id[0]; u8 cpumode; if (intel_pt_skip_event(pt)) @@ -2719,7 +2720,7 @@ static void intel_pt_set_event_name(struct evlist *evlist, u64 id, struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->id && evsel->id[0] == id) { + if (evsel->core.id && evsel->core.id[0] == id) { if (evsel->name) zfree(&evsel->name); evsel->name = strdup(name); @@ -2734,7 +2735,7 @@ static struct evsel *intel_pt_evsel(struct intel_pt *pt, struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->core.attr.type == pt->pmu_type && evsel->ids) + if (evsel->core.attr.type == pt->pmu_type && evsel->core.ids) return evsel; } @@ -2775,7 +2776,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_id_all = evsel->core.attr.sample_id_all; attr.read_format = evsel->core.attr.read_format; - id = evsel->id[0] + 1000000000; + id = evsel->core.id[0] + 1000000000; if (!id) id = 1; @@ -2902,7 +2903,7 @@ static void intel_pt_setup_pebs_events(struct intel_pt *pt) return; evlist__for_each_entry(pt->session->evlist, evsel) { - if (evsel->core.attr.aux_output && evsel->id) { + if (evsel->core.attr.aux_output && evsel->core.id) { pt->sample_pebs = true; pt->pebs_evsel = evsel; return; diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index b80f29bfc7bb..1bdf4c6ea3e5 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -15,7 +15,6 @@ #include <linux/stringify.h> #include "build-id.h" -#include "util.h" #include "event.h" #include "debug.h" #include "evlist.h" @@ -27,7 +26,6 @@ #include "jit.h" #include "jitdump.h" #include "genelf.h" -#include "../builtin.h" #include <linux/ctype.h> #include <linux/zalloc.h> @@ -779,7 +777,7 @@ jit_process(struct perf_session *session, * track sample_type to compute id_all layout * perf sets the same sample type to all events as of now */ - first = perf_evlist__first(session->evlist); + first = evlist__first(session->evlist); jd.sample_type = first->core.attr.sample_type; *nbytes = 0; diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 46913637085b..6f0fa05b62b6 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -2,6 +2,8 @@ #ifndef __PERF_KVM_STAT_H #define __PERF_KVM_STAT_H +#ifdef HAVE_KVM_STAT_SUPPORT + #include "tool.h" #include "stat.h" #include "record.h" @@ -144,5 +146,7 @@ extern const int decode_str_len; extern const char *kvm_exit_reason; extern const char *kvm_entry_trace; extern const char *kvm_exit_trace; +#endif /* HAVE_KVM_STAT_SUPPORT */ +extern int kvm_add_default_arch_event(int *argc, const char **argv); #endif /* __PERF_KVM_STAT_H */ diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/arm64.c index 66756e6be111..6b4e5a0892f8 100644 --- a/tools/perf/util/libunwind/arm64.c +++ b/tools/perf/util/libunwind/arm64.c @@ -22,7 +22,6 @@ #define LIBUNWIND__ARCH_REG_SP PERF_REG_ARM64_SP #include "unwind.h" -#include "debug.h" #include "libunwind-aarch64.h" #include <../../../../arch/arm64/include/uapi/asm/perf_regs.h> #include "../../arch/arm64/util/unwind-libunwind.c" diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind/x86_32.c index c5e568188e19..21c216c40a3b 100644 --- a/tools/perf/util/libunwind/x86_32.c +++ b/tools/perf/util/libunwind/x86_32.c @@ -22,7 +22,6 @@ #define LIBUNWIND__ARCH_REG_SP PERF_REG_X86_SP #include "unwind.h" -#include "debug.h" #include "libunwind-x86.h" #include <../../../../arch/x86/include/uapi/asm/perf_regs.h> diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 55fb4b3b1157..8d04e3d070b1 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -8,6 +8,7 @@ #include <limits.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <linux/err.h> #include <linux/string.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index 397447066033..39062df02629 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -7,10 +7,10 @@ #include <sys/stat.h> #include <fcntl.h> #include "compress.h" -#include "util.h" #include "debug.h" #include <string.h> #include <unistd.h> +#include <internal/lib.h> #define BUFSIZE 8192 diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b4749d3eed08..70a9f8716a4b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -32,6 +32,7 @@ #include "linux/hash.h" #include "asm/bug.h" #include "bpf-event.h" +#include <internal/lib.h> // page_size #include <linux/ctype.h> #include <symbol/kallsyms.h> @@ -2609,21 +2610,6 @@ int machines__for_each_thread(struct machines *machines, return rc; } -int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, - struct target *target, struct perf_thread_map *threads, - perf_event__handler_t process, bool data_mmap, - unsigned int nr_threads_synthesize) -{ - if (target__has_task(target)) - return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); - else if (target__has_cpu(target)) - return perf_event__synthesize_threads(tool, process, - machine, data_mmap, - nr_threads_synthesize); - /* command specified */ - return 0; -} - pid_t machine__get_current_tid(struct machine *machine, int cpu) { int nr_cpus = min(machine->env->nr_cpus_online, MAX_NR_CPUS); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index ffd391a925a6..18e13c0ccd6a 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -6,7 +6,6 @@ #include <linux/rbtree.h> #include "map_groups.h" #include "dsos.h" -#include "event.h" #include "rwsem.h" struct addr_location; @@ -252,20 +251,6 @@ int machines__for_each_thread(struct machines *machines, int (*fn)(struct thread *thread, void *p), void *priv); -int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, - struct target *target, struct perf_thread_map *threads, - perf_event__handler_t process, bool data_mmap, - unsigned int nr_threads_synthesize); -static inline -int machine__synthesize_threads(struct machine *machine, struct target *target, - struct perf_thread_map *threads, bool data_mmap, - unsigned int nr_threads_synthesize) -{ - return __machine__synthesize_threads(machine, NULL, target, threads, - perf_event__process, data_mmap, - nr_threads_synthesize); -} - pid_t machine__get_current_tid(struct machine *machine, int cpu); int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, pid_t tid); diff --git a/tools/perf/util/memswap.h b/tools/perf/util/memswap.h index 1e29ff903ca9..2c38e8c2d548 100644 --- a/tools/perf/util/memswap.h +++ b/tools/perf/util/memswap.h @@ -2,6 +2,13 @@ #ifndef PERF_MEMSWAP_H_ #define PERF_MEMSWAP_H_ +#include <linux/types.h> + +union u64_swap { + u64 val64; + u32 val32[2]; +}; + void mem_bswap_64(void *src, int byte_size); void mem_bswap_32(void *src, int byte_size); diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 33c5b5495482..a35dc57d5995 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -12,6 +12,7 @@ #include <linux/zalloc.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> // sysconf() #ifdef HAVE_LIBNUMA_SUPPORT #include <numaif.h> #endif @@ -20,25 +21,25 @@ #include "event.h" #include "mmap.h" #include "../perf.h" -#include "util.h" /* page_size */ +#include <internal/lib.h> /* page_size */ -size_t perf_mmap__mmap_len(struct perf_mmap *map) +size_t perf_mmap__mmap_len(struct mmap *map) { - return map->mask + 1 + page_size; + return map->core.mask + 1 + page_size; } /* When check_messup is true, 'end' must points to a good entry */ -static union perf_event *perf_mmap__read(struct perf_mmap *map, +static union perf_event *perf_mmap__read(struct mmap *map, u64 *startp, u64 end) { - unsigned char *data = map->base + page_size; + unsigned char *data = map->core.base + page_size; union perf_event *event = NULL; int diff = end - *startp; if (diff >= (int)sizeof(event->header)) { size_t size; - event = (union perf_event *)&data[*startp & map->mask]; + event = (union perf_event *)&data[*startp & map->core.mask]; size = event->header.size; if (size < sizeof(event->header) || diff < (int)size) @@ -48,20 +49,20 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map, * Event straddles the mmap boundary -- header should always * be inside due to u64 alignment of output. */ - if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) { + if ((*startp & map->core.mask) + size != ((*startp + size) & map->core.mask)) { unsigned int offset = *startp; unsigned int len = min(sizeof(*event), size), cpy; - void *dst = map->event_copy; + void *dst = map->core.event_copy; do { - cpy = min(map->mask + 1 - (offset & map->mask), len); - memcpy(dst, &data[offset & map->mask], cpy); + cpy = min(map->core.mask + 1 - (offset & map->core.mask), len); + memcpy(dst, &data[offset & map->core.mask], cpy); offset += cpy; dst += cpy; len -= cpy; } while (len); - event = (union perf_event *)map->event_copy; + event = (union perf_event *)map->core.event_copy; } *startp += size; @@ -82,55 +83,55 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map, * } * perf_mmap__read_done() */ -union perf_event *perf_mmap__read_event(struct perf_mmap *map) +union perf_event *perf_mmap__read_event(struct mmap *map) { union perf_event *event; /* * Check if event was unmapped due to a POLLHUP/POLLERR. */ - if (!refcount_read(&map->refcnt)) + if (!refcount_read(&map->core.refcnt)) return NULL; /* non-overwirte doesn't pause the ringbuffer */ - if (!map->overwrite) - map->end = perf_mmap__read_head(map); + if (!map->core.overwrite) + map->core.end = perf_mmap__read_head(map); - event = perf_mmap__read(map, &map->start, map->end); + event = perf_mmap__read(map, &map->core.start, map->core.end); - if (!map->overwrite) - map->prev = map->start; + if (!map->core.overwrite) + map->core.prev = map->core.start; return event; } -static bool perf_mmap__empty(struct perf_mmap *map) +static bool perf_mmap__empty(struct mmap *map) { - return perf_mmap__read_head(map) == map->prev && !map->auxtrace_mmap.base; + return perf_mmap__read_head(map) == map->core.prev && !map->auxtrace_mmap.base; } -void perf_mmap__get(struct perf_mmap *map) +void perf_mmap__get(struct mmap *map) { - refcount_inc(&map->refcnt); + refcount_inc(&map->core.refcnt); } -void perf_mmap__put(struct perf_mmap *map) +void perf_mmap__put(struct mmap *map) { - BUG_ON(map->base && refcount_read(&map->refcnt) == 0); + BUG_ON(map->core.base && refcount_read(&map->core.refcnt) == 0); - if (refcount_dec_and_test(&map->refcnt)) + if (refcount_dec_and_test(&map->core.refcnt)) perf_mmap__munmap(map); } -void perf_mmap__consume(struct perf_mmap *map) +void perf_mmap__consume(struct mmap *map) { - if (!map->overwrite) { - u64 old = map->prev; + if (!map->core.overwrite) { + u64 old = map->core.prev; perf_mmap__write_tail(map, old); } - if (refcount_read(&map->refcnt) == 1 && perf_mmap__empty(map)) + if (refcount_read(&map->core.refcnt) == 1 && perf_mmap__empty(map)) perf_mmap__put(map); } @@ -161,13 +162,13 @@ void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __mayb } #ifdef HAVE_AIO_SUPPORT -static int perf_mmap__aio_enabled(struct perf_mmap *map) +static int perf_mmap__aio_enabled(struct mmap *map) { return map->aio.nr_cblocks > 0; } #ifdef HAVE_LIBNUMA_SUPPORT -static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) +static int perf_mmap__aio_alloc(struct mmap *map, int idx) { map->aio.data[idx] = mmap(NULL, perf_mmap__mmap_len(map), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); @@ -179,7 +180,7 @@ static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) return 0; } -static void perf_mmap__aio_free(struct perf_mmap *map, int idx) +static void perf_mmap__aio_free(struct mmap *map, int idx) { if (map->aio.data[idx]) { munmap(map->aio.data[idx], perf_mmap__mmap_len(map)); @@ -187,7 +188,7 @@ static void perf_mmap__aio_free(struct perf_mmap *map, int idx) } } -static int perf_mmap__aio_bind(struct perf_mmap *map, int idx, int cpu, int affinity) +static int perf_mmap__aio_bind(struct mmap *map, int idx, int cpu, int affinity) { void *data; size_t mmap_len; @@ -207,7 +208,7 @@ static int perf_mmap__aio_bind(struct perf_mmap *map, int idx, int cpu, int affi return 0; } #else /* !HAVE_LIBNUMA_SUPPORT */ -static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) +static int perf_mmap__aio_alloc(struct mmap *map, int idx) { map->aio.data[idx] = malloc(perf_mmap__mmap_len(map)); if (map->aio.data[idx] == NULL) @@ -216,19 +217,19 @@ static int perf_mmap__aio_alloc(struct perf_mmap *map, int idx) return 0; } -static void perf_mmap__aio_free(struct perf_mmap *map, int idx) +static void perf_mmap__aio_free(struct mmap *map, int idx) { zfree(&(map->aio.data[idx])); } -static int perf_mmap__aio_bind(struct perf_mmap *map __maybe_unused, int idx __maybe_unused, +static int perf_mmap__aio_bind(struct mmap *map __maybe_unused, int idx __maybe_unused, int cpu __maybe_unused, int affinity __maybe_unused) { return 0; } #endif -static int perf_mmap__aio_mmap(struct perf_mmap *map, struct mmap_params *mp) +static int perf_mmap__aio_mmap(struct mmap *map, struct mmap_params *mp) { int delta_max, i, prio, ret; @@ -256,7 +257,7 @@ static int perf_mmap__aio_mmap(struct perf_mmap *map, struct mmap_params *mp) pr_debug2("failed to allocate data buffer area, error %m"); return -1; } - ret = perf_mmap__aio_bind(map, i, map->cpu, mp->affinity); + ret = perf_mmap__aio_bind(map, i, map->core.cpu, mp->affinity); if (ret == -1) return -1; /* @@ -282,7 +283,7 @@ static int perf_mmap__aio_mmap(struct perf_mmap *map, struct mmap_params *mp) return 0; } -static void perf_mmap__aio_munmap(struct perf_mmap *map) +static void perf_mmap__aio_munmap(struct mmap *map) { int i; @@ -294,34 +295,34 @@ static void perf_mmap__aio_munmap(struct perf_mmap *map) zfree(&map->aio.aiocb); } #else /* !HAVE_AIO_SUPPORT */ -static int perf_mmap__aio_enabled(struct perf_mmap *map __maybe_unused) +static int perf_mmap__aio_enabled(struct mmap *map __maybe_unused) { return 0; } -static int perf_mmap__aio_mmap(struct perf_mmap *map __maybe_unused, +static int perf_mmap__aio_mmap(struct mmap *map __maybe_unused, struct mmap_params *mp __maybe_unused) { return 0; } -static void perf_mmap__aio_munmap(struct perf_mmap *map __maybe_unused) +static void perf_mmap__aio_munmap(struct mmap *map __maybe_unused) { } #endif -void perf_mmap__munmap(struct perf_mmap *map) +void perf_mmap__munmap(struct mmap *map) { perf_mmap__aio_munmap(map); if (map->data != NULL) { munmap(map->data, perf_mmap__mmap_len(map)); map->data = NULL; } - if (map->base != NULL) { - munmap(map->base, perf_mmap__mmap_len(map)); - map->base = NULL; - map->fd = -1; - refcount_set(&map->refcnt, 0); + if (map->core.base != NULL) { + munmap(map->core.base, perf_mmap__mmap_len(map)); + map->core.base = NULL; + map->core.fd = -1; + refcount_set(&map->core.refcnt, 0); } auxtrace_mmap__munmap(&map->auxtrace_mmap); } @@ -343,16 +344,16 @@ static void build_node_mask(int node, cpu_set_t *mask) } } -static void perf_mmap__setup_affinity_mask(struct perf_mmap *map, struct mmap_params *mp) +static void perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params *mp) { CPU_ZERO(&map->affinity_mask); if (mp->affinity == PERF_AFFINITY_NODE && cpu__max_node() > 1) - build_node_mask(cpu__get_node(map->cpu), &map->affinity_mask); + build_node_mask(cpu__get_node(map->core.cpu), &map->affinity_mask); else if (mp->affinity == PERF_AFFINITY_CPU) - CPU_SET(map->cpu, &map->affinity_mask); + CPU_SET(map->core.cpu, &map->affinity_mask); } -int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu) +int perf_mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) { /* * The last one will be done at perf_mmap__consume(), so that we @@ -367,23 +368,23 @@ int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int c * evlist layer can't just drop it when filtering events in * perf_evlist__filter_pollfd(). */ - refcount_set(&map->refcnt, 2); - map->prev = 0; - map->mask = mp->mask; - map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, + refcount_set(&map->core.refcnt, 2); + map->core.prev = 0; + map->core.mask = mp->mask; + map->core.base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, MAP_SHARED, fd, 0); - if (map->base == MAP_FAILED) { + if (map->core.base == MAP_FAILED) { pr_debug2("failed to mmap perf event ring buffer, error %d\n", errno); - map->base = NULL; + map->core.base = NULL; return -1; } - map->fd = fd; - map->cpu = cpu; + map->core.fd = fd; + map->core.cpu = cpu; perf_mmap__setup_affinity_mask(map, mp); - map->flush = mp->flush; + map->core.flush = mp->flush; map->comp_level = mp->comp_level; @@ -399,7 +400,7 @@ int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int c } if (auxtrace_mmap__mmap(&map->auxtrace_mmap, - &mp->auxtrace_mp, map->base, fd)) + &mp->auxtrace_mp, map->core.base, fd)) return -1; return perf_mmap__aio_mmap(map, mp); @@ -440,25 +441,25 @@ static int overwrite_rb_find_range(void *buf, int mask, u64 *start, u64 *end) /* * Report the start and end of the available data in ringbuffer */ -static int __perf_mmap__read_init(struct perf_mmap *md) +static int __perf_mmap__read_init(struct mmap *md) { u64 head = perf_mmap__read_head(md); - u64 old = md->prev; - unsigned char *data = md->base + page_size; + u64 old = md->core.prev; + unsigned char *data = md->core.base + page_size; unsigned long size; - md->start = md->overwrite ? head : old; - md->end = md->overwrite ? old : head; + md->core.start = md->core.overwrite ? head : old; + md->core.end = md->core.overwrite ? old : head; - if ((md->end - md->start) < md->flush) + if ((md->core.end - md->core.start) < md->core.flush) return -EAGAIN; - size = md->end - md->start; - if (size > (unsigned long)(md->mask) + 1) { - if (!md->overwrite) { + size = md->core.end - md->core.start; + if (size > (unsigned long)(md->core.mask) + 1) { + if (!md->core.overwrite) { WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); - md->prev = head; + md->core.prev = head; perf_mmap__consume(md); return -EAGAIN; } @@ -467,29 +468,29 @@ static int __perf_mmap__read_init(struct perf_mmap *md) * Backward ring buffer is full. We still have a chance to read * most of data from it. */ - if (overwrite_rb_find_range(data, md->mask, &md->start, &md->end)) + if (overwrite_rb_find_range(data, md->core.mask, &md->core.start, &md->core.end)) return -EINVAL; } return 0; } -int perf_mmap__read_init(struct perf_mmap *map) +int perf_mmap__read_init(struct mmap *map) { /* * Check if event was unmapped due to a POLLHUP/POLLERR. */ - if (!refcount_read(&map->refcnt)) + if (!refcount_read(&map->core.refcnt)) return -ENOENT; return __perf_mmap__read_init(map); } -int perf_mmap__push(struct perf_mmap *md, void *to, - int push(struct perf_mmap *map, void *to, void *buf, size_t size)) +int perf_mmap__push(struct mmap *md, void *to, + int push(struct mmap *map, void *to, void *buf, size_t size)) { u64 head = perf_mmap__read_head(md); - unsigned char *data = md->base + page_size; + unsigned char *data = md->core.base + page_size; unsigned long size; void *buf; int rc = 0; @@ -498,12 +499,12 @@ int perf_mmap__push(struct perf_mmap *md, void *to, if (rc < 0) return (rc == -EAGAIN) ? 1 : -1; - size = md->end - md->start; + size = md->core.end - md->core.start; - if ((md->start & md->mask) + size != (md->end & md->mask)) { - buf = &data[md->start & md->mask]; - size = md->mask + 1 - (md->start & md->mask); - md->start += size; + if ((md->core.start & md->core.mask) + size != (md->core.end & md->core.mask)) { + buf = &data[md->core.start & md->core.mask]; + size = md->core.mask + 1 - (md->core.start & md->core.mask); + md->core.start += size; if (push(md, to, buf, size) < 0) { rc = -1; @@ -511,16 +512,16 @@ int perf_mmap__push(struct perf_mmap *md, void *to, } } - buf = &data[md->start & md->mask]; - size = md->end - md->start; - md->start += size; + buf = &data[md->core.start & md->core.mask]; + size = md->core.end - md->core.start; + md->core.start += size; if (push(md, to, buf, size) < 0) { rc = -1; goto out; } - md->prev = head; + md->core.prev = head; perf_mmap__consume(md); out: return rc; @@ -529,16 +530,16 @@ out: /* * Mandatory for overwrite mode * The direction of overwrite mode is backward. - * The last perf_mmap__read() will set tail to map->prev. - * Need to correct the map->prev to head which is the end of next read. + * The last perf_mmap__read() will set tail to map->core.prev. + * Need to correct the map->core.prev to head which is the end of next read. */ -void perf_mmap__read_done(struct perf_mmap *map) +void perf_mmap__read_done(struct mmap *map) { /* * Check if event was unmapped due to a POLLHUP/POLLERR. */ - if (!refcount_read(&map->refcnt)) + if (!refcount_read(&map->core.refcnt)) return; - map->prev = perf_mmap__read_head(map); + map->core.prev = perf_mmap__read_head(map); } diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index 3857a49e8f96..e567c1c875bd 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -1,6 +1,7 @@ #ifndef __PERF_MMAP_H #define __PERF_MMAP_H 1 +#include <internal/mmap.h> #include <linux/compiler.h> #include <linux/refcount.h> #include <linux/types.h> @@ -15,22 +16,13 @@ struct aiocb; /** - * struct perf_mmap - perf's ring buffer mmap details + * struct mmap - perf's ring buffer mmap details * * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this */ -struct perf_mmap { - void *base; - int mask; - int fd; - int cpu; - refcount_t refcnt; - u64 prev; - u64 start; - u64 end; - bool overwrite; +struct mmap { + struct perf_mmap core; struct auxtrace_mmap auxtrace_mmap; - char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); #ifdef HAVE_AIO_SUPPORT struct { void **data; @@ -40,71 +32,42 @@ struct perf_mmap { } aio; #endif cpu_set_t affinity_mask; - u64 flush; void *data; int comp_level; }; -/* - * State machine of bkw_mmap_state: - * - * .________________(forbid)_____________. - * | V - * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY - * ^ ^ | ^ | - * | |__(forbid)____/ |___(forbid)___/| - * | | - * \_________________(3)_______________/ - * - * NOTREADY : Backward ring buffers are not ready - * RUNNING : Backward ring buffers are recording - * DATA_PENDING : We are required to collect data from backward ring buffers - * EMPTY : We have collected data from backward ring buffers. - * - * (0): Setup backward ring buffer - * (1): Pause ring buffers for reading - * (2): Read from ring buffers - * (3): Resume ring buffers for recording - */ -enum bkw_mmap_state { - BKW_MMAP_NOTREADY, - BKW_MMAP_RUNNING, - BKW_MMAP_DATA_PENDING, - BKW_MMAP_EMPTY, -}; - struct mmap_params { int prot, mask, nr_cblocks, affinity, flush, comp_level; struct auxtrace_mmap_params auxtrace_mp; }; -int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu); -void perf_mmap__munmap(struct perf_mmap *map); +int perf_mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu); +void perf_mmap__munmap(struct mmap *map); -void perf_mmap__get(struct perf_mmap *map); -void perf_mmap__put(struct perf_mmap *map); +void perf_mmap__get(struct mmap *map); +void perf_mmap__put(struct mmap *map); -void perf_mmap__consume(struct perf_mmap *map); +void perf_mmap__consume(struct mmap *map); -static inline u64 perf_mmap__read_head(struct perf_mmap *mm) +static inline u64 perf_mmap__read_head(struct mmap *mm) { - return ring_buffer_read_head(mm->base); + return ring_buffer_read_head(mm->core.base); } -static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail) +static inline void perf_mmap__write_tail(struct mmap *md, u64 tail) { - ring_buffer_write_tail(md->base, tail); + ring_buffer_write_tail(md->core.base, tail); } -union perf_event *perf_mmap__read_forward(struct perf_mmap *map); +union perf_event *perf_mmap__read_forward(struct mmap *map); -union perf_event *perf_mmap__read_event(struct perf_mmap *map); +union perf_event *perf_mmap__read_event(struct mmap *map); -int perf_mmap__push(struct perf_mmap *md, void *to, - int push(struct perf_mmap *map, void *to, void *buf, size_t size)); +int perf_mmap__push(struct mmap *md, void *to, + int push(struct mmap *map, void *to, void *buf, size_t size)); -size_t perf_mmap__mmap_len(struct perf_mmap *map); +size_t perf_mmap__mmap_len(struct mmap *map); -int perf_mmap__read_init(struct perf_mmap *md); -void perf_mmap__read_done(struct perf_mmap *map); +int perf_mmap__read_init(struct mmap *md); +void perf_mmap__read_done(struct mmap *map); #endif /*__PERF_MMAP_H */ diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index 99be15dd2b6b..285d6f30d912 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c @@ -17,8 +17,26 @@ #include <string.h> #include <unistd.h> #include <asm/bug.h> +#include <linux/kernel.h> #include <linux/zalloc.h> +static const char *perf_ns__names[] = { + [NET_NS_INDEX] = "net", + [UTS_NS_INDEX] = "uts", + [IPC_NS_INDEX] = "ipc", + [PID_NS_INDEX] = "pid", + [USER_NS_INDEX] = "user", + [MNT_NS_INDEX] = "mnt", + [CGROUP_NS_INDEX] = "cgroup", +}; + +const char *perf_ns__name(unsigned int id) +{ + if (id >= ARRAY_SIZE(perf_ns__names)) + return "UNKNOWN"; + return perf_ns__names[id]; +} + struct namespaces *namespaces__new(struct perf_record_namespaces *event) { struct namespaces *namespaces; diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h index 40edef56cb52..4b33f684eddd 100644 --- a/tools/perf/util/namespaces.h +++ b/tools/perf/util/namespaces.h @@ -66,4 +66,6 @@ static inline void __nsinfo__zput(struct nsinfo **nsip) #define nsinfo__zput(nsi) __nsinfo__zput(&nsi) +const char *perf_ns__name(unsigned int id); + #endif /* __PERF_NAMESPACES_H */ diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5ec21d21113c..b5e2adef49de 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -30,11 +30,12 @@ #include "parse-events-flex.h" #include "pmu.h" #include "thread_map.h" -#include "cpumap.h" #include "probe-file.h" #include "asm/bug.h" #include "util/parse-branch-options.h" #include "metricgroup.h" +#include "util/evsel_config.h" +#include "util/event.h" #define MAX_NAME_LEN 100 @@ -335,7 +336,7 @@ __add_event(struct list_head *list, int *idx, (*idx)++; evsel->core.cpus = perf_cpu_map__get(cpus); evsel->core.own_cpus = perf_cpu_map__get(cpus); - evsel->system_wide = pmu ? pmu->is_uncore : false; + evsel->core.system_wide = pmu ? pmu->is_uncore : false; evsel->auto_merge_stats = auto_merge_stats; if (name) @@ -1936,7 +1937,7 @@ int parse_events(struct evlist *evlist, const char *str, perf_evlist__splice_list_tail(evlist, &parse_state.list); evlist->nr_groups += parse_state.nr_groups; - last = perf_evlist__last(evlist); + last = evlist__last(evlist); last->cmdline_group_boundary = true; return 0; @@ -2050,7 +2051,7 @@ foreach_evsel_in_last_glob(struct evlist *evlist, * So no need to WARN here, let *func do this. */ if (evlist->core.nr_entries > 0) - last = perf_evlist__last(evlist); + last = evlist__last(evlist); do { err = (*func)(last, arg); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index f1c36ed1cf36..48126ae4cd13 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -9,13 +9,11 @@ #define YYDEBUG 1 #include <fnmatch.h> +#include <stdio.h> #include <linux/compiler.h> -#include <linux/list.h> #include <linux/types.h> -#include "util.h" #include "pmu.h" #include "evsel.h" -#include "debug.h" #include "parse-events.h" #include "parse-events-bison.h" diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c index e635c594f773..7a0ab3507bd5 100644 --- a/tools/perf/util/perf-hooks.c +++ b/tools/perf/util/perf-hooks.c @@ -12,7 +12,6 @@ #include <setjmp.h> #include <linux/err.h> #include <linux/kernel.h> -#include "util/util.h" #include "util/debug.h" #include "util/perf-hooks.h" diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c new file mode 100644 index 000000000000..d4ad3f04923a --- /dev/null +++ b/tools/perf/util/perf_event_attr_fprintf.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <inttypes.h> +#include <stdio.h> +#include <stdbool.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/perf_event.h> +#include "util/evsel_fprintf.h" + +struct bit_names { + int bit; + const char *name; +}; + +static void __p_bits(char *buf, size_t size, u64 value, struct bit_names *bits) +{ + bool first_bit = true; + int i = 0; + + do { + if (value & bits[i].bit) { + buf += scnprintf(buf, size, "%s%s", first_bit ? "" : "|", bits[i].name); + first_bit = false; + } + } while (bits[++i].name != NULL); +} + +static void __p_sample_type(char *buf, size_t size, u64 value) +{ +#define bit_name(n) { PERF_SAMPLE_##n, #n } + struct bit_names bits[] = { + bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR), + bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), + bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), + bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), + bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), + bit_name(WEIGHT), bit_name(PHYS_ADDR), + { .name = NULL, } + }; +#undef bit_name + __p_bits(buf, size, value, bits); +} + +static void __p_branch_sample_type(char *buf, size_t size, u64 value) +{ +#define bit_name(n) { PERF_SAMPLE_BRANCH_##n, #n } + struct bit_names bits[] = { + bit_name(USER), bit_name(KERNEL), bit_name(HV), bit_name(ANY), + bit_name(ANY_CALL), bit_name(ANY_RETURN), bit_name(IND_CALL), + bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX), + bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), + bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), + { .name = NULL, } + }; +#undef bit_name + __p_bits(buf, size, value, bits); +} + +static void __p_read_format(char *buf, size_t size, u64 value) +{ +#define bit_name(n) { PERF_FORMAT_##n, #n } + struct bit_names bits[] = { + bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING), + bit_name(ID), bit_name(GROUP), + { .name = NULL, } + }; +#undef bit_name + __p_bits(buf, size, value, bits); +} + +#define BUF_SIZE 1024 + +#define p_hex(val) snprintf(buf, BUF_SIZE, "%#"PRIx64, (uint64_t)(val)) +#define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) +#define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) +#define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) +#define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) +#define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) + +#define PRINT_ATTRn(_n, _f, _p) \ +do { \ + if (attr->_f) { \ + _p(attr->_f); \ + ret += attr__fprintf(fp, _n, buf, priv);\ + } \ +} while (0) + +#define PRINT_ATTRf(_f, _p) PRINT_ATTRn(#_f, _f, _p) + +int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, + attr__fprintf_f attr__fprintf, void *priv) +{ + char buf[BUF_SIZE]; + int ret = 0; + + PRINT_ATTRf(type, p_unsigned); + PRINT_ATTRf(size, p_unsigned); + PRINT_ATTRf(config, p_hex); + PRINT_ATTRn("{ sample_period, sample_freq }", sample_period, p_unsigned); + PRINT_ATTRf(sample_type, p_sample_type); + PRINT_ATTRf(read_format, p_read_format); + + PRINT_ATTRf(disabled, p_unsigned); + PRINT_ATTRf(inherit, p_unsigned); + PRINT_ATTRf(pinned, p_unsigned); + PRINT_ATTRf(exclusive, p_unsigned); + PRINT_ATTRf(exclude_user, p_unsigned); + PRINT_ATTRf(exclude_kernel, p_unsigned); + PRINT_ATTRf(exclude_hv, p_unsigned); + PRINT_ATTRf(exclude_idle, p_unsigned); + PRINT_ATTRf(mmap, p_unsigned); + PRINT_ATTRf(comm, p_unsigned); + PRINT_ATTRf(freq, p_unsigned); + PRINT_ATTRf(inherit_stat, p_unsigned); + PRINT_ATTRf(enable_on_exec, p_unsigned); + PRINT_ATTRf(task, p_unsigned); + PRINT_ATTRf(watermark, p_unsigned); + PRINT_ATTRf(precise_ip, p_unsigned); + PRINT_ATTRf(mmap_data, p_unsigned); + PRINT_ATTRf(sample_id_all, p_unsigned); + PRINT_ATTRf(exclude_host, p_unsigned); + PRINT_ATTRf(exclude_guest, p_unsigned); + PRINT_ATTRf(exclude_callchain_kernel, p_unsigned); + PRINT_ATTRf(exclude_callchain_user, p_unsigned); + PRINT_ATTRf(mmap2, p_unsigned); + PRINT_ATTRf(comm_exec, p_unsigned); + PRINT_ATTRf(use_clockid, p_unsigned); + PRINT_ATTRf(context_switch, p_unsigned); + PRINT_ATTRf(write_backward, p_unsigned); + PRINT_ATTRf(namespaces, p_unsigned); + PRINT_ATTRf(ksymbol, p_unsigned); + PRINT_ATTRf(bpf_event, p_unsigned); + PRINT_ATTRf(aux_output, p_unsigned); + + PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); + PRINT_ATTRf(bp_type, p_unsigned); + PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); + PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); + PRINT_ATTRf(branch_sample_type, p_branch_sample_type); + PRINT_ATTRf(sample_regs_user, p_hex); + PRINT_ATTRf(sample_stack_user, p_unsigned); + PRINT_ATTRf(clockid, p_signed); + PRINT_ATTRf(sample_regs_intr, p_hex); + PRINT_ATTRf(aux_watermark, p_unsigned); + PRINT_ATTRf(sample_max_stack, p_unsigned); + + return ret; +} diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index fb597fa94234..5608da82ad23 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -20,7 +20,6 @@ #include "debug.h" #include "pmu.h" #include "parse-events.h" -#include "cpumap.h" #include "header.h" #include "pmu-events/pmu-events.h" #include "string2.h" diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b8e0967c5c21..91cab5f669d2 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2331,6 +2331,7 @@ void clear_probe_trace_event(struct probe_trace_event *tev) } } zfree(&tev->args); + tev->nargs = 0; } struct kprobe_blacklist_node { diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index d13db55a2feb..b659466ea498 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -16,6 +16,7 @@ #include "strlist.h" #include "strfilter.h" #include "debug.h" +#include "build-id.h" #include "dso.h" #include "color.h" #include "symbol.h" diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 505905fc21c5..cd9f95e5044e 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1245,6 +1245,17 @@ static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, return n; } +static bool trace_event_finder_overlap(struct trace_event_finder *tf) +{ + int i; + + for (i = 0; i < tf->ntevs; i++) { + if (tf->pf.addr == tf->tevs[i].point.address) + return true; + } + return false; +} + /* Add a found probe point into trace event list */ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) { @@ -1255,6 +1266,14 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) struct perf_probe_arg *args = NULL; int ret, i; + /* + * For some reason (e.g. different column assigned to same address) + * This callback can be called with the address which already passed. + * Ignore it first. + */ + if (trace_event_finder_overlap(tf)) + return 0; + /* Check number of tevs */ if (tf->ntevs == tf->max_tevs) { pr_warning("Too many( > %d) probe point found.\n", diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index c6dd478956f1..9af183860fbd 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -10,6 +10,7 @@ util/python.c util/cap.c util/evlist.c util/evsel.c +util/perf_event_attr_fprintf.c util/cpumap.c util/memswap.c util/mmap.c diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 07ca4535e6f7..53f31053a27a 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -6,17 +6,15 @@ #include <linux/err.h> #include <perf/cpumap.h> #include <traceevent/event-parse.h> -#include "debug.h" #include "evlist.h" #include "callchain.h" #include "evsel.h" #include "event.h" -#include "cpumap.h" #include "print_binary.h" #include "thread_map.h" #include "trace-event.h" #include "mmap.h" -#include "util.h" +#include <internal/lib.h> #include "../perf-sys.h" #if PY_MAJOR_VERSION < 3 @@ -61,6 +59,8 @@ int parse_callchain_record(const char *arg __maybe_unused, */ int verbose; +int eprintf(int level, int var, const char *fmt, ...); + int eprintf(int level, int var, const char *fmt, ...) { va_list args; @@ -884,7 +884,7 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist, static void pyrf_evlist__delete(struct pyrf_evlist *pevlist) { - perf_evlist__exit(&pevlist->evlist); + evlist__exit(&pevlist->evlist); Py_TYPE(pevlist)->tp_free((PyObject*)pevlist); } @@ -899,7 +899,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, &pages, &overwrite)) return NULL; - if (perf_evlist__mmap(evlist, pages) < 0) { + if (evlist__mmap(evlist, pages) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -918,7 +918,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) return NULL; - n = perf_evlist__poll(evlist, timeout); + n = evlist__poll(evlist, timeout); if (n < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -935,17 +935,17 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, PyObject *list = PyList_New(0); int i; - for (i = 0; i < evlist->pollfd.nr; ++i) { + for (i = 0; i < evlist->core.pollfd.nr; ++i) { PyObject *file; #if PY_MAJOR_VERSION < 3 - FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r"); + FILE *fp = fdopen(evlist->core.pollfd.entries[i].fd, "r"); if (fp == NULL) goto free_list; file = PyFile_FromFile(fp, "perf", "r", NULL); #else - file = PyFile_FromFd(evlist->pollfd.entries[i].fd, "perf", "r", -1, + file = PyFile_FromFd(evlist->core.pollfd.entries[i].fd, "perf", "r", -1, NULL, NULL, NULL, 0); #endif if (file == NULL) @@ -984,14 +984,14 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, return Py_BuildValue("i", evlist->core.nr_entries); } -static struct perf_mmap *get_md(struct evlist *evlist, int cpu) +static struct mmap *get_md(struct evlist *evlist, int cpu) { int i; - for (i = 0; i < evlist->nr_mmaps; i++) { - struct perf_mmap *md = &evlist->mmap[i]; + for (i = 0; i < evlist->core.nr_mmaps; i++) { + struct mmap *md = &evlist->mmap[i]; - if (md->cpu == cpu) + if (md->core.cpu == cpu) return md; } @@ -1005,7 +1005,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, union perf_event *event; int sample_id_all = 1, cpu; static char *kwlist[] = { "cpu", "sample_id_all", NULL }; - struct perf_mmap *md; + struct mmap *md; int err; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 286fe816c0f3..8579505c29a4 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -2,7 +2,6 @@ #include "debug.h" #include "evlist.h" #include "evsel.h" -#include "cpumap.h" #include "parse-events.h" #include <errno.h> #include <limits.h> @@ -10,7 +9,6 @@ #include <api/fs/fs.h> #include <subcmd/parse-options.h> #include <perf/cpumap.h> -#include "util.h" #include "cloexec.h" #include "record.h" #include "../perf-sys.h" @@ -32,7 +30,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) if (parse_events(evlist, str, NULL)) goto out_delete; - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); while (1) { fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); @@ -173,7 +171,7 @@ void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, use_sample_identifier = perf_can_sample_identifier(); sample_id = true; } else if (evlist->core.nr_entries > 1) { - struct evsel *first = perf_evlist__first(evlist); + struct evsel *first = evlist__first(evlist); evlist__for_each_entry(evlist, evsel) { if (evsel->core.attr.sample_type == first->core.attr.sample_type) @@ -278,7 +276,7 @@ bool perf_evlist__can_select_event(struct evlist *evlist, const char *str) if (err) goto out_delete; - evsel = perf_evlist__last(temp_evlist); + evsel = evlist__last(temp_evlist); if (!evlist || perf_cpu_map__empty(evlist->core.cpus)) { struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); diff --git a/tools/perf/util/rwsem.c b/tools/perf/util/rwsem.c index 5e52e7baa7b6..f3d29d8ddc99 100644 --- a/tools/perf/util/rwsem.c +++ b/tools/perf/util/rwsem.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 #include "util.h" #include "rwsem.h" diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c index 24a99909d8b3..6785cd87aa4d 100644 --- a/tools/perf/util/s390-cpumsf.c +++ b/tools/perf/util/s390-cpumsf.c @@ -151,7 +151,6 @@ #include <sys/stat.h> #include <sys/types.h> -#include "cpumap.h" #include "color.h" #include "evsel.h" #include "evlist.h" diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index 4d9593e331ea..05b43ab4eeef 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -22,7 +22,6 @@ #include <asm/byteorder.h> #include "debug.h" -#include "util.h" #include "session.h" #include "evlist.h" #include "color.h" diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 666a56e88d8e..5d341efc3237 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -37,7 +37,6 @@ #include "../dso.h" #include "../callchain.h" #include "../evsel.h" -#include "../util.h" #include "../event.h" #include "../thread.h" #include "../comm.h" @@ -49,7 +48,6 @@ #include "map.h" #include "symbol.h" #include "thread_map.h" -#include "cpumap.h" #include "print_binary.h" #include "stat.h" #include "mem-events.h" diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e9e4a04f15db..061bb4d6a3f5 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -22,7 +22,6 @@ #include "symbol.h" #include "session.h" #include "tool.h" -#include "cpumap.h" #include "perf_regs.h" #include "asm/bug.h" #include "auxtrace.h" @@ -30,10 +29,11 @@ #include "thread-stack.h" #include "sample-raw.h" #include "stat.h" -#include "util.h" #include "ui/progress.h" #include "../perf.h" #include "arch/common.h" +#include <internal/lib.h> +#include <linux/err.h> #ifdef HAVE_ZSTD_SUPPORT static int perf_session__process_compressed_event(struct perf_session *session, @@ -187,6 +187,7 @@ static int ordered_events__deliver_event(struct ordered_events *oe, struct perf_session *perf_session__new(struct perf_data *data, bool repipe, struct perf_tool *tool) { + int ret = -ENOMEM; struct perf_session *session = zalloc(sizeof(*session)); if (!session) @@ -201,13 +202,15 @@ struct perf_session *perf_session__new(struct perf_data *data, perf_env__init(&session->header.env); if (data) { - if (perf_data__open(data)) + ret = perf_data__open(data); + if (ret < 0) goto out_delete; session->data = data; if (perf_data__is_read(data)) { - if (perf_session__open(session) < 0) + ret = perf_session__open(session); + if (ret < 0) goto out_delete; /* @@ -222,8 +225,11 @@ struct perf_session *perf_session__new(struct perf_data *data, perf_evlist__init_trace_event_sample_raw(session->evlist); /* Open the directory data. */ - if (data->is_dir && perf_data__open_dir(data)) + if (data->is_dir) { + ret = perf_data__open_dir(data); + if (ret) goto out_delete; + } } } else { session->machines.host.env = &perf_env; @@ -256,7 +262,7 @@ struct perf_session *perf_session__new(struct perf_data *data, out_delete: perf_session__delete(session); out: - return NULL; + return ERR_PTR(ret); } static void perf_session__delete_threads(struct perf_session *session) @@ -1317,6 +1323,7 @@ static int deliver_sample_value(struct evlist *evlist, struct machine *machine) { struct perf_sample_id *sid = perf_evlist__id2sid(evlist, v->id); + struct evsel *evsel; if (sid) { sample->id = v->id; @@ -1336,7 +1343,8 @@ static int deliver_sample_value(struct evlist *evlist, if (!sample->period) return 0; - return tool->sample(tool, event, sample, sid->evsel, machine); + evsel = container_of(sid->evsel, struct evsel, core); + return tool->sample(tool, event, sample, evsel, machine); } static int deliver_sample_group(struct evlist *evlist, @@ -2412,73 +2420,3 @@ int perf_event__process_id_index(struct perf_session *session, } return 0; } - -int perf_event__synthesize_id_index(struct perf_tool *tool, - perf_event__handler_t process, - struct evlist *evlist, - struct machine *machine) -{ - union perf_event *ev; - struct evsel *evsel; - size_t nr = 0, i = 0, sz, max_nr, n; - int err; - - pr_debug2("Synthesizing id index\n"); - - max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / - sizeof(struct id_index_entry); - - evlist__for_each_entry(evlist, evsel) - nr += evsel->ids; - - n = nr > max_nr ? max_nr : nr; - sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); - ev = zalloc(sz); - if (!ev) - return -ENOMEM; - - ev->id_index.header.type = PERF_RECORD_ID_INDEX; - ev->id_index.header.size = sz; - ev->id_index.nr = n; - - evlist__for_each_entry(evlist, evsel) { - u32 j; - - for (j = 0; j < evsel->ids; j++) { - struct id_index_entry *e; - struct perf_sample_id *sid; - - if (i >= n) { - err = process(tool, ev, NULL, machine); - if (err) - goto out_err; - nr -= n; - i = 0; - } - - e = &ev->id_index.entries[i++]; - - e->id = evsel->id[j]; - - sid = perf_evlist__id2sid(evlist, e->id); - if (!sid) { - free(ev); - return -ENOENT; - } - - e->idx = sid->idx; - e->cpu = sid->cpu; - e->tid = sid->tid; - } - } - - sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); - ev->id_index.header.size = sz; - ev->id_index.nr = nr; - - err = process(tool, ev, NULL, machine); -out_err: - free(ev); - - return err; -} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b7aa076ab6fd..b4c9428c18f0 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -138,9 +138,4 @@ int perf_session__deliver_synth_event(struct perf_session *session, int perf_event__process_id_index(struct perf_session *session, union perf_event *event); -int perf_event__synthesize_id_index(struct perf_tool *tool, - perf_event__handler_t process, - struct evlist *evlist, - struct machine *machine); - #endif /* __PERF_SESSION_H */ diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index a2308eb77681..43d1d410854a 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2329,7 +2329,7 @@ static struct evsel *find_evsel(struct evlist *evlist, char *event_name) if (nr > evlist->core.nr_entries) return NULL; - evsel = perf_evlist__first(evlist); + evsel = evlist__first(evlist); while (--nr > 0) evsel = perf_evsel__next(evsel); diff --git a/tools/perf/util/srccode.c b/tools/perf/util/srccode.c index adfcf1ff464c..d84ed8b6caaa 100644 --- a/tools/perf/util/srccode.c +++ b/tools/perf/util/srccode.c @@ -15,7 +15,7 @@ #include <string.h> #include "srccode.h" #include "debug.h" -#include "util.h" +#include <internal/lib.h> // page_size #define MAXSRCCACHE (32*1024*1024) #define MAXSRCFILES 64 diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 70c87fdb2a43..2c41d47f6f83 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -738,6 +738,8 @@ static void generic_metric(struct perf_stat_config *config, char *n, *pn; expr__ctx_init(&pctx); + /* Must be first id entry */ + expr__add_id(&pctx, name, avg); for (i = 0; metric_events[i]; i++) { struct saved_value *v; struct stats *stats; @@ -776,8 +778,6 @@ static void generic_metric(struct perf_stat_config *config, expr__add_id(&pctx, n, avg_stats(stats)*scale); } - expr__add_id(&pctx, name, avg); - if (!metric_events[i]) { const char *p = metric_expr; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 8f1ea27f976f..ebdd130557fb 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -4,6 +4,7 @@ #include <math.h> #include <string.h> #include "counts.h" +#include "cpumap.h" #include "debug.h" #include "header.h" #include "stat.h" @@ -161,6 +162,15 @@ static void perf_evsel__free_prev_raw_counts(struct evsel *evsel) evsel->prev_raw_counts = NULL; } +static void perf_evsel__reset_prev_raw_counts(struct evsel *evsel) +{ + if (evsel->prev_raw_counts) { + evsel->prev_raw_counts->aggr.val = 0; + evsel->prev_raw_counts->aggr.ena = 0; + evsel->prev_raw_counts->aggr.run = 0; + } +} + static int perf_evsel__alloc_stats(struct evsel *evsel, bool alloc_raw) { int ncpus = perf_evsel__nr_cpus(evsel); @@ -211,6 +221,14 @@ void perf_evlist__reset_stats(struct evlist *evlist) } } +void perf_evlist__reset_prev_raw_counts(struct evlist *evlist) +{ + struct evsel *evsel; + + evlist__for_each_entry(evlist, evsel) + perf_evsel__reset_prev_raw_counts(evsel); +} + static void zero_per_pkg(struct evsel *counter) { if (counter->per_pkg_mask) @@ -318,7 +336,7 @@ static int process_counter_maps(struct perf_stat_config *config, int ncpus = perf_evsel__nr_cpus(counter); int cpu, thread; - if (counter->system_wide) + if (counter->core.system_wide) nthreads = 1; for (thread = 0; thread < nthreads; thread++) { @@ -493,45 +511,3 @@ int create_perf_stat_counter(struct evsel *evsel, return perf_evsel__open_per_thread(evsel, evsel->core.threads); } - -int perf_stat_synthesize_config(struct perf_stat_config *config, - struct perf_tool *tool, - struct evlist *evlist, - perf_event__handler_t process, - bool attrs) -{ - int err; - - if (attrs) { - err = perf_event__synthesize_attrs(tool, evlist, process); - if (err < 0) { - pr_err("Couldn't synthesize attrs.\n"); - return err; - } - } - - err = perf_event__synthesize_extra_attr(tool, evlist, process, - attrs); - - err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, - process, NULL); - if (err < 0) { - pr_err("Couldn't synthesize thread map.\n"); - return err; - } - - err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, - process, NULL); - if (err < 0) { - pr_err("Couldn't synthesize thread map.\n"); - return err; - } - - err = perf_event__synthesize_stat_config(tool, config, process, NULL); - if (err < 0) { - pr_err("Couldn't synthesize config.\n"); - return err; - } - - return 0; -} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 14fe3e548229..edbeb2f63e8d 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -7,8 +7,9 @@ #include <sys/types.h> #include <sys/resource.h> #include "rblist.h" -#include "event.h" +struct perf_cpu_map; +struct perf_stat_config; struct timespec; struct stats { @@ -192,6 +193,7 @@ void perf_stat__collect_metric_expr(struct evlist *); int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw); void perf_evlist__free_stats(struct evlist *evlist); void perf_evlist__reset_stats(struct evlist *evlist); +void perf_evlist__reset_prev_raw_counts(struct evlist *evlist); int perf_stat_process_counter(struct perf_stat_config *config, struct evsel *counter); @@ -210,11 +212,6 @@ size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, struct target *target); -int perf_stat_synthesize_config(struct perf_stat_config *config, - struct perf_tool *tool, - struct evlist *evlist, - perf_event__handler_t process, - bool attrs); void perf_evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 582f4a69cd48..96f941e01681 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -17,11 +17,11 @@ #include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> +#include <internal/cpumap.h> #include <perf/cpumap.h> #include "env.h" #include "svghelper.h" -#include "cpumap.h" static u64 first_time, last_time; static u64 turbo_frequency, max_freq; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 9428639872a6..66f4be1df573 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -7,6 +7,7 @@ #include <unistd.h> #include <inttypes.h> +#include "dso.h" #include "map.h" #include "map_groups.h" #include "symbol.h" @@ -16,10 +17,12 @@ #include "machine.h" #include "vdso.h" #include "debug.h" -#include "util.h" +#include "util/copyfile.h" #include <linux/ctype.h> +#include <linux/kernel.h> #include <linux/zalloc.h> #include <symbol/kallsyms.h> +#include <internal/lib.h> #ifndef EM_AARCH64 #define EM_AARCH64 183 /* ARM 64 bit */ diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 7e2813ec9498..d6e99af263ec 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -1,8 +1,6 @@ -// SPDX-License-Identifier: GPL-2.0 #include "dso.h" #include "symbol.h" #include "symsrc.h" -#include "util.h" #include <errno.h> #include <unistd.h> @@ -13,6 +11,7 @@ #include <byteswap.h> #include <sys/stat.h> #include <linux/zalloc.h> +#include <internal/lib.h> static bool check_need_swap(int file_endian) { diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 765c75df2904..a8f80e427674 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -19,7 +19,7 @@ #include "build-id.h" #include "cap.h" #include "dso.h" -#include "util.h" +#include "util.h" // lsdir() #include "debug.h" #include "event.h" #include "machine.h" diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c new file mode 100644 index 000000000000..807cbca403a7 --- /dev/null +++ b/tools/perf/util/synthetic-events.c @@ -0,0 +1,1884 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "util/debug.h" +#include "util/dso.h" +#include "util/event.h" +#include "util/evlist.h" +#include "util/machine.h" +#include "util/map.h" +#include "util/map_symbol.h" +#include "util/branch.h" +#include "util/memswap.h" +#include "util/namespaces.h" +#include "util/session.h" +#include "util/stat.h" +#include "util/symbol.h" +#include "util/synthetic-events.h" +#include "util/target.h" +#include "util/time-utils.h" +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/zalloc.h> +#include <linux/perf_event.h> +#include <asm/bug.h> +#include <perf/evsel.h> +#include <internal/cpumap.h> +#include <perf/cpumap.h> +#include <internal/lib.h> // page_size +#include <internal/threadmap.h> +#include <perf/threadmap.h> +#include <symbol/kallsyms.h> +#include <dirent.h> +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ +#include <api/fs/fs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 + +unsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT; + +int perf_tool__process_synth_event(struct perf_tool *tool, + union perf_event *event, + struct machine *machine, + perf_event__handler_t process) +{ + struct perf_sample synth_sample = { + .pid = -1, + .tid = -1, + .time = -1, + .stream_id = -1, + .cpu = -1, + .period = 1, + .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK, + }; + + return process(tool, event, &synth_sample, machine); +}; + +/* + * Assumes that the first 4095 bytes of /proc/pid/stat contains + * the comm, tgid and ppid. + */ +static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, + pid_t *tgid, pid_t *ppid) +{ + char filename[PATH_MAX]; + char bf[4096]; + int fd; + size_t size = 0; + ssize_t n; + char *name, *tgids, *ppids; + + *tgid = -1; + *ppid = -1; + + snprintf(filename, sizeof(filename), "/proc/%d/status", pid); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + pr_debug("couldn't open %s\n", filename); + return -1; + } + + n = read(fd, bf, sizeof(bf) - 1); + close(fd); + if (n <= 0) { + pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", + pid); + return -1; + } + bf[n] = '\0'; + + name = strstr(bf, "Name:"); + tgids = strstr(bf, "Tgid:"); + ppids = strstr(bf, "PPid:"); + + if (name) { + char *nl; + + name = skip_spaces(name + 5); /* strlen("Name:") */ + nl = strchr(name, '\n'); + if (nl) + *nl = '\0'; + + size = strlen(name); + if (size >= len) + size = len - 1; + memcpy(comm, name, size); + comm[size] = '\0'; + } else { + pr_debug("Name: string not found for pid %d\n", pid); + } + + if (tgids) { + tgids += 5; /* strlen("Tgid:") */ + *tgid = atoi(tgids); + } else { + pr_debug("Tgid: string not found for pid %d\n", pid); + } + + if (ppids) { + ppids += 5; /* strlen("PPid:") */ + *ppid = atoi(ppids); + } else { + pr_debug("PPid: string not found for pid %d\n", pid); + } + + return 0; +} + +static int perf_event__prepare_comm(union perf_event *event, pid_t pid, + struct machine *machine, + pid_t *tgid, pid_t *ppid) +{ + size_t size; + + *ppid = -1; + + memset(&event->comm, 0, sizeof(event->comm)); + + if (machine__is_host(machine)) { + if (perf_event__get_comm_ids(pid, event->comm.comm, + sizeof(event->comm.comm), + tgid, ppid) != 0) { + return -1; + } + } else { + *tgid = machine->pid; + } + + if (*tgid < 0) + return -1; + + event->comm.pid = *tgid; + event->comm.header.type = PERF_RECORD_COMM; + + size = strlen(event->comm.comm) + 1; + size = PERF_ALIGN(size, sizeof(u64)); + memset(event->comm.comm + size, 0, machine->id_hdr_size); + event->comm.header.size = (sizeof(event->comm) - + (sizeof(event->comm.comm) - size) + + machine->id_hdr_size); + event->comm.tid = pid; + + return 0; +} + +pid_t perf_event__synthesize_comm(struct perf_tool *tool, + union perf_event *event, pid_t pid, + perf_event__handler_t process, + struct machine *machine) +{ + pid_t tgid, ppid; + + if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) + return -1; + + if (perf_tool__process_synth_event(tool, event, machine, process) != 0) + return -1; + + return tgid; +} + +static void perf_event__get_ns_link_info(pid_t pid, const char *ns, + struct perf_ns_link_info *ns_link_info) +{ + struct stat64 st; + char proc_ns[128]; + + sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns); + if (stat64(proc_ns, &st) == 0) { + ns_link_info->dev = st.st_dev; + ns_link_info->ino = st.st_ino; + } +} + +int perf_event__synthesize_namespaces(struct perf_tool *tool, + union perf_event *event, + pid_t pid, pid_t tgid, + perf_event__handler_t process, + struct machine *machine) +{ + u32 idx; + struct perf_ns_link_info *ns_link_info; + + if (!tool || !tool->namespace_events) + return 0; + + memset(&event->namespaces, 0, (sizeof(event->namespaces) + + (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + + machine->id_hdr_size)); + + event->namespaces.pid = tgid; + event->namespaces.tid = pid; + + event->namespaces.nr_namespaces = NR_NAMESPACES; + + ns_link_info = event->namespaces.link_info; + + for (idx = 0; idx < event->namespaces.nr_namespaces; idx++) + perf_event__get_ns_link_info(pid, perf_ns__name(idx), + &ns_link_info[idx]); + + event->namespaces.header.type = PERF_RECORD_NAMESPACES; + + event->namespaces.header.size = (sizeof(event->namespaces) + + (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + + machine->id_hdr_size); + + if (perf_tool__process_synth_event(tool, event, machine, process) != 0) + return -1; + + return 0; +} + +static int perf_event__synthesize_fork(struct perf_tool *tool, + union perf_event *event, + pid_t pid, pid_t tgid, pid_t ppid, + perf_event__handler_t process, + struct machine *machine) +{ + memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); + + /* + * for main thread set parent to ppid from status file. For other + * threads set parent pid to main thread. ie., assume main thread + * spawns all threads in a process + */ + if (tgid == pid) { + event->fork.ppid = ppid; + event->fork.ptid = ppid; + } else { + event->fork.ppid = tgid; + event->fork.ptid = tgid; + } + event->fork.pid = tgid; + event->fork.tid = pid; + event->fork.header.type = PERF_RECORD_FORK; + event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC; + + event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); + + if (perf_tool__process_synth_event(tool, event, machine, process) != 0) + return -1; + + return 0; +} + +int perf_event__synthesize_mmap_events(struct perf_tool *tool, + union perf_event *event, + pid_t pid, pid_t tgid, + perf_event__handler_t process, + struct machine *machine, + bool mmap_data) +{ + char filename[PATH_MAX]; + FILE *fp; + unsigned long long t; + bool truncation = false; + unsigned long long timeout = proc_map_timeout * 1000000ULL; + int rc = 0; + const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); + int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; + + if (machine__is_default_guest(machine)) + return 0; + + snprintf(filename, sizeof(filename), "%s/proc/%d/task/%d/maps", + machine->root_dir, pid, pid); + + fp = fopen(filename, "r"); + if (fp == NULL) { + /* + * We raced with a task exiting - just return: + */ + pr_debug("couldn't open %s\n", filename); + return -1; + } + + event->header.type = PERF_RECORD_MMAP2; + t = rdclock(); + + while (1) { + char bf[BUFSIZ]; + char prot[5]; + char execname[PATH_MAX]; + char anonstr[] = "//anon"; + unsigned int ino; + size_t size; + ssize_t n; + + if (fgets(bf, sizeof(bf), fp) == NULL) + break; + + if ((rdclock() - t) > timeout) { + pr_warning("Reading %s time out. " + "You may want to increase " + "the time limit by --proc-map-timeout\n", + filename); + truncation = true; + goto out; + } + + /* ensure null termination since stack will be reused. */ + strcpy(execname, ""); + + /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ + n = sscanf(bf, "%"PRI_lx64"-%"PRI_lx64" %s %"PRI_lx64" %x:%x %u %[^\n]\n", + &event->mmap2.start, &event->mmap2.len, prot, + &event->mmap2.pgoff, &event->mmap2.maj, + &event->mmap2.min, + &ino, execname); + + /* + * Anon maps don't have the execname. + */ + if (n < 7) + continue; + + event->mmap2.ino = (u64)ino; + + /* + * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c + */ + if (machine__is_host(machine)) + event->header.misc = PERF_RECORD_MISC_USER; + else + event->header.misc = PERF_RECORD_MISC_GUEST_USER; + + /* map protection and flags bits */ + event->mmap2.prot = 0; + event->mmap2.flags = 0; + if (prot[0] == 'r') + event->mmap2.prot |= PROT_READ; + if (prot[1] == 'w') + event->mmap2.prot |= PROT_WRITE; + if (prot[2] == 'x') + event->mmap2.prot |= PROT_EXEC; + + if (prot[3] == 's') + event->mmap2.flags |= MAP_SHARED; + else + event->mmap2.flags |= MAP_PRIVATE; + + if (prot[2] != 'x') { + if (!mmap_data || prot[0] != 'r') + continue; + + event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; + } + +out: + if (truncation) + event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; + + if (!strcmp(execname, "")) + strcpy(execname, anonstr); + + if (hugetlbfs_mnt_len && + !strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) { + strcpy(execname, anonstr); + event->mmap2.flags |= MAP_HUGETLB; + } + + size = strlen(execname) + 1; + memcpy(event->mmap2.filename, execname, size); + size = PERF_ALIGN(size, sizeof(u64)); + event->mmap2.len -= event->mmap.start; + event->mmap2.header.size = (sizeof(event->mmap2) - + (sizeof(event->mmap2.filename) - size)); + memset(event->mmap2.filename + size, 0, machine->id_hdr_size); + event->mmap2.header.size += machine->id_hdr_size; + event->mmap2.pid = tgid; + event->mmap2.tid = pid; + + if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { + rc = -1; + break; + } + + if (truncation) + break; + } + + fclose(fp); + return rc; +} + +int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, + struct machine *machine) +{ + int rc = 0; + struct map *pos; + struct maps *maps = machine__kernel_maps(machine); + union perf_event *event = zalloc((sizeof(event->mmap) + + machine->id_hdr_size)); + if (event == NULL) { + pr_debug("Not enough memory synthesizing mmap event " + "for kernel modules\n"); + return -1; + } + + event->header.type = PERF_RECORD_MMAP; + + /* + * kernel uses 0 for user space maps, see kernel/perf_event.c + * __perf_event_mmap + */ + if (machine__is_host(machine)) + event->header.misc = PERF_RECORD_MISC_KERNEL; + else + event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; + + for (pos = maps__first(maps); pos; pos = map__next(pos)) { + size_t size; + + if (!__map__is_kmodule(pos)) + continue; + + size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); + event->mmap.header.type = PERF_RECORD_MMAP; + event->mmap.header.size = (sizeof(event->mmap) - + (sizeof(event->mmap.filename) - size)); + memset(event->mmap.filename + size, 0, machine->id_hdr_size); + event->mmap.header.size += machine->id_hdr_size; + event->mmap.start = pos->start; + event->mmap.len = pos->end - pos->start; + event->mmap.pid = machine->pid; + + memcpy(event->mmap.filename, pos->dso->long_name, + pos->dso->long_name_len + 1); + if (perf_tool__process_synth_event(tool, event, machine, process) != 0) { + rc = -1; + break; + } + } + + free(event); + return rc; +} + +static int __event__synthesize_thread(union perf_event *comm_event, + union perf_event *mmap_event, + union perf_event *fork_event, + union perf_event *namespaces_event, + pid_t pid, int full, perf_event__handler_t process, + struct perf_tool *tool, struct machine *machine, bool mmap_data) +{ + char filename[PATH_MAX]; + DIR *tasks; + struct dirent *dirent; + pid_t tgid, ppid; + int rc = 0; + + /* special case: only send one comm event using passed in pid */ + if (!full) { + tgid = perf_event__synthesize_comm(tool, comm_event, pid, + process, machine); + + if (tgid == -1) + return -1; + + if (perf_event__synthesize_namespaces(tool, namespaces_event, pid, + tgid, process, machine) < 0) + return -1; + + /* + * send mmap only for thread group leader + * see thread__init_map_groups + */ + if (pid == tgid && + perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, + process, machine, mmap_data)) + return -1; + + return 0; + } + + if (machine__is_default_guest(machine)) + return 0; + + snprintf(filename, sizeof(filename), "%s/proc/%d/task", + machine->root_dir, pid); + + tasks = opendir(filename); + if (tasks == NULL) { + pr_debug("couldn't open %s\n", filename); + return 0; + } + + while ((dirent = readdir(tasks)) != NULL) { + char *end; + pid_t _pid; + + _pid = strtol(dirent->d_name, &end, 10); + if (*end) + continue; + + rc = -1; + if (perf_event__prepare_comm(comm_event, _pid, machine, + &tgid, &ppid) != 0) + break; + + if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, + ppid, process, machine) < 0) + break; + + if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid, + tgid, process, machine) < 0) + break; + + /* + * Send the prepared comm event + */ + if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0) + break; + + rc = 0; + if (_pid == pid) { + /* process the parent's maps too */ + rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, + process, machine, mmap_data); + if (rc) + break; + } + } + + closedir(tasks); + return rc; +} + +int perf_event__synthesize_thread_map(struct perf_tool *tool, + struct perf_thread_map *threads, + perf_event__handler_t process, + struct machine *machine, + bool mmap_data) +{ + union perf_event *comm_event, *mmap_event, *fork_event; + union perf_event *namespaces_event; + int err = -1, thread, j; + + comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); + if (comm_event == NULL) + goto out; + + mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); + if (mmap_event == NULL) + goto out_free_comm; + + fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); + if (fork_event == NULL) + goto out_free_mmap; + + namespaces_event = malloc(sizeof(namespaces_event->namespaces) + + (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + + machine->id_hdr_size); + if (namespaces_event == NULL) + goto out_free_fork; + + err = 0; + for (thread = 0; thread < threads->nr; ++thread) { + if (__event__synthesize_thread(comm_event, mmap_event, + fork_event, namespaces_event, + perf_thread_map__pid(threads, thread), 0, + process, tool, machine, + mmap_data)) { + err = -1; + break; + } + + /* + * comm.pid is set to thread group id by + * perf_event__synthesize_comm + */ + if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { + bool need_leader = true; + + /* is thread group leader in thread_map? */ + for (j = 0; j < threads->nr; ++j) { + if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { + need_leader = false; + break; + } + } + + /* if not, generate events for it */ + if (need_leader && + __event__synthesize_thread(comm_event, mmap_event, + fork_event, namespaces_event, + comm_event->comm.pid, 0, + process, tool, machine, + mmap_data)) { + err = -1; + break; + } + } + } + free(namespaces_event); +out_free_fork: + free(fork_event); +out_free_mmap: + free(mmap_event); +out_free_comm: + free(comm_event); +out: + return err; +} + +static int __perf_event__synthesize_threads(struct perf_tool *tool, + perf_event__handler_t process, + struct machine *machine, + bool mmap_data, + struct dirent **dirent, + int start, + int num) +{ + union perf_event *comm_event, *mmap_event, *fork_event; + union perf_event *namespaces_event; + int err = -1; + char *end; + pid_t pid; + int i; + + comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); + if (comm_event == NULL) + goto out; + + mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size); + if (mmap_event == NULL) + goto out_free_comm; + + fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); + if (fork_event == NULL) + goto out_free_mmap; + + namespaces_event = malloc(sizeof(namespaces_event->namespaces) + + (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) + + machine->id_hdr_size); + if (namespaces_event == NULL) + goto out_free_fork; + + for (i = start; i < start + num; i++) { + if (!isdigit(dirent[i]->d_name[0])) + continue; + + pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); + /* only interested in proper numerical dirents */ + if (*end) + continue; + /* + * We may race with exiting thread, so don't stop just because + * one thread couldn't be synthesized. + */ + __event__synthesize_thread(comm_event, mmap_event, fork_event, + namespaces_event, pid, 1, process, + tool, machine, mmap_data); + } + err = 0; + + free(namespaces_event); +out_free_fork: + free(fork_event); +out_free_mmap: + free(mmap_event); +out_free_comm: + free(comm_event); +out: + return err; +} + +struct synthesize_threads_arg { + struct perf_tool *tool; + perf_event__handler_t process; + struct machine *machine; + bool mmap_data; + struct dirent **dirent; + int num; + int start; +}; + +static void *synthesize_threads_worker(void *arg) +{ + struct synthesize_threads_arg *args = arg; + + __perf_event__synthesize_threads(args->tool, args->process, + args->machine, args->mmap_data, + args->dirent, + args->start, args->num); + return NULL; +} + +int perf_event__synthesize_threads(struct perf_tool *tool, + perf_event__handler_t process, + struct machine *machine, + bool mmap_data, + unsigned int nr_threads_synthesize) +{ + struct synthesize_threads_arg *args = NULL; + pthread_t *synthesize_threads = NULL; + char proc_path[PATH_MAX]; + struct dirent **dirent; + int num_per_thread; + int m, n, i, j; + int thread_nr; + int base = 0; + int err = -1; + + + if (machine__is_default_guest(machine)) + return 0; + + snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); + n = scandir(proc_path, &dirent, 0, alphasort); + if (n < 0) + return err; + + if (nr_threads_synthesize == UINT_MAX) + thread_nr = sysconf(_SC_NPROCESSORS_ONLN); + else + thread_nr = nr_threads_synthesize; + + if (thread_nr <= 1) { + err = __perf_event__synthesize_threads(tool, process, + machine, mmap_data, + dirent, base, n); + goto free_dirent; + } + if (thread_nr > n) + thread_nr = n; + + synthesize_threads = calloc(sizeof(pthread_t), thread_nr); + if (synthesize_threads == NULL) + goto free_dirent; + + args = calloc(sizeof(*args), thread_nr); + if (args == NULL) + goto free_threads; + + num_per_thread = n / thread_nr; + m = n % thread_nr; + for (i = 0; i < thread_nr; i++) { + args[i].tool = tool; + args[i].process = process; + args[i].machine = machine; + args[i].mmap_data = mmap_data; + args[i].dirent = dirent; + } + for (i = 0; i < m; i++) { + args[i].num = num_per_thread + 1; + args[i].start = i * args[i].num; + } + if (i != 0) + base = args[i-1].start + args[i-1].num; + for (j = i; j < thread_nr; j++) { + args[j].num = num_per_thread; + args[j].start = base + (j - i) * args[i].num; + } + + for (i = 0; i < thread_nr; i++) { + if (pthread_create(&synthesize_threads[i], NULL, + synthesize_threads_worker, &args[i])) + goto out_join; + } + err = 0; +out_join: + for (i = 0; i < thread_nr; i++) + pthread_join(synthesize_threads[i], NULL); + free(args); +free_threads: + free(synthesize_threads); +free_dirent: + for (i = 0; i < n; i++) + zfree(&dirent[i]); + free(dirent); + + return err; +} + +int __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused, + perf_event__handler_t process __maybe_unused, + struct machine *machine __maybe_unused) +{ + return 0; +} + +static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, + perf_event__handler_t process, + struct machine *machine) +{ + size_t size; + struct map *map = machine__kernel_map(machine); + struct kmap *kmap; + int err; + union perf_event *event; + + if (map == NULL) + return -1; + + kmap = map__kmap(map); + if (!kmap->ref_reloc_sym) + return -1; + + /* + * We should get this from /sys/kernel/sections/.text, but till that is + * available use this, and after it is use this as a fallback for older + * kernels. + */ + event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); + if (event == NULL) { + pr_debug("Not enough memory synthesizing mmap event " + "for kernel modules\n"); + return -1; + } + + if (machine__is_host(machine)) { + /* + * kernel uses PERF_RECORD_MISC_USER for user space maps, + * see kernel/perf_event.c __perf_event_mmap + */ + event->header.misc = PERF_RECORD_MISC_KERNEL; + } else { + event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; + } + + size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), + "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; + size = PERF_ALIGN(size, sizeof(u64)); + event->mmap.header.type = PERF_RECORD_MMAP; + event->mmap.header.size = (sizeof(event->mmap) - + (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); + event->mmap.pgoff = kmap->ref_reloc_sym->addr; + event->mmap.start = map->start; + event->mmap.len = map->end - event->mmap.start; + event->mmap.pid = machine->pid; + + err = perf_tool__process_synth_event(tool, event, machine, process); + free(event); + + return err; +} + +int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, + perf_event__handler_t process, + struct machine *machine) +{ + int err; + + err = __perf_event__synthesize_kernel_mmap(tool, process, machine); + if (err < 0) + return err; + + return perf_event__synthesize_extra_kmaps(tool, process, machine); +} + +int perf_event__synthesize_thread_map2(struct perf_tool *tool, + struct perf_thread_map *threads, + perf_event__handler_t process, + struct machine *machine) +{ + union perf_event *event; + int i, err, size; + + size = sizeof(event->thread_map); + size += threads->nr * sizeof(event->thread_map.entries[0]); + + event = zalloc(size); + if (!event) + return -ENOMEM; + + event->header.type = PERF_RECORD_THREAD_MAP; + event->header.size = size; + event->thread_map.nr = threads->nr; + + for (i = 0; i < threads->nr; i++) { + struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; + char *comm = perf_thread_map__comm(threads, i); + + if (!comm) + comm = (char *) ""; + + entry->pid = perf_thread_map__pid(threads, i); + strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); + } + + err = process(tool, event, NULL, machine); + + free(event); + return err; +} + +static void synthesize_cpus(struct cpu_map_entries *cpus, + struct perf_cpu_map *map) +{ + int i; + + cpus->nr = map->nr; + + for (i = 0; i < map->nr; i++) + cpus->cpu[i] = map->map[i]; +} + +static void synthesize_mask(struct perf_record_record_cpu_map *mask, + struct perf_cpu_map *map, int max) +{ + int i; + + mask->nr = BITS_TO_LONGS(max); + mask->long_size = sizeof(long); + + for (i = 0; i < map->nr; i++) + set_bit(map->map[i], mask->mask); +} + +static size_t cpus_size(struct perf_cpu_map *map) +{ + return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); +} + +static size_t mask_size(struct perf_cpu_map *map, int *max) +{ + int i; + + *max = 0; + + for (i = 0; i < map->nr; i++) { + /* bit possition of the cpu is + 1 */ + int bit = map->map[i] + 1; + + if (bit > *max) + *max = bit; + } + + return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); +} + +void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) +{ + size_t size_cpus, size_mask; + bool is_dummy = perf_cpu_map__empty(map); + + /* + * Both array and mask data have variable size based + * on the number of cpus and their actual values. + * The size of the 'struct perf_record_cpu_map_data' is: + * + * array = size of 'struct cpu_map_entries' + + * number of cpus * sizeof(u64) + * + * mask = size of 'struct perf_record_record_cpu_map' + + * maximum cpu bit converted to size of longs + * + * and finaly + the size of 'struct perf_record_cpu_map_data'. + */ + size_cpus = cpus_size(map); + size_mask = mask_size(map, max); + + if (is_dummy || (size_cpus < size_mask)) { + *size += size_cpus; + *type = PERF_CPU_MAP__CPUS; + } else { + *size += size_mask; + *type = PERF_CPU_MAP__MASK; + } + + *size += sizeof(struct perf_record_cpu_map_data); + *size = PERF_ALIGN(*size, sizeof(u64)); + return zalloc(*size); +} + +void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, + u16 type, int max) +{ + data->type = type; + + switch (type) { + case PERF_CPU_MAP__CPUS: + synthesize_cpus((struct cpu_map_entries *) data->data, map); + break; + case PERF_CPU_MAP__MASK: + synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); + default: + break; + }; +} + +static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) +{ + size_t size = sizeof(struct perf_record_cpu_map); + struct perf_record_cpu_map *event; + int max; + u16 type; + + event = cpu_map_data__alloc(map, &size, &type, &max); + if (!event) + return NULL; + + event->header.type = PERF_RECORD_CPU_MAP; + event->header.size = size; + event->data.type = type; + + cpu_map_data__synthesize(&event->data, map, type, max); + return event; +} + +int perf_event__synthesize_cpu_map(struct perf_tool *tool, + struct perf_cpu_map *map, + perf_event__handler_t process, + struct machine *machine) +{ + struct perf_record_cpu_map *event; + int err; + + event = cpu_map_event__new(map); + if (!event) + return -ENOMEM; + + err = process(tool, (union perf_event *) event, NULL, machine); + + free(event); + return err; +} + +int perf_event__synthesize_stat_config(struct perf_tool *tool, + struct perf_stat_config *config, + perf_event__handler_t process, + struct machine *machine) +{ + struct perf_record_stat_config *event; + int size, i = 0, err; + + size = sizeof(*event); + size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0])); + + event = zalloc(size); + if (!event) + return -ENOMEM; + + event->header.type = PERF_RECORD_STAT_CONFIG; + event->header.size = size; + event->nr = PERF_STAT_CONFIG_TERM__MAX; + +#define ADD(__term, __val) \ + event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \ + event->data[i].val = __val; \ + i++; + + ADD(AGGR_MODE, config->aggr_mode) + ADD(INTERVAL, config->interval) + ADD(SCALE, config->scale) + + WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX, + "stat config terms unbalanced\n"); +#undef ADD + + err = process(tool, (union perf_event *) event, NULL, machine); + + free(event); + return err; +} + +int perf_event__synthesize_stat(struct perf_tool *tool, + u32 cpu, u32 thread, u64 id, + struct perf_counts_values *count, + perf_event__handler_t process, + struct machine *machine) +{ + struct perf_record_stat event; + + event.header.type = PERF_RECORD_STAT; + event.header.size = sizeof(event); + event.header.misc = 0; + + event.id = id; + event.cpu = cpu; + event.thread = thread; + event.val = count->val; + event.ena = count->ena; + event.run = count->run; + + return process(tool, (union perf_event *) &event, NULL, machine); +} + +int perf_event__synthesize_stat_round(struct perf_tool *tool, + u64 evtime, u64 type, + perf_event__handler_t process, + struct machine *machine) +{ + struct perf_record_stat_round event; + + event.header.type = PERF_RECORD_STAT_ROUND; + event.header.size = sizeof(event); + event.header.misc = 0; + + event.time = evtime; + event.type = type; + + return process(tool, (union perf_event *) &event, NULL, machine); +} + +size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) +{ + size_t sz, result = sizeof(struct perf_record_sample); + + if (type & PERF_SAMPLE_IDENTIFIER) + result += sizeof(u64); + + if (type & PERF_SAMPLE_IP) + result += sizeof(u64); + + if (type & PERF_SAMPLE_TID) + result += sizeof(u64); + + if (type & PERF_SAMPLE_TIME) + result += sizeof(u64); + + if (type & PERF_SAMPLE_ADDR) + result += sizeof(u64); + + if (type & PERF_SAMPLE_ID) + result += sizeof(u64); + + if (type & PERF_SAMPLE_STREAM_ID) + result += sizeof(u64); + + if (type & PERF_SAMPLE_CPU) + result += sizeof(u64); + + if (type & PERF_SAMPLE_PERIOD) + result += sizeof(u64); + + if (type & PERF_SAMPLE_READ) { + result += sizeof(u64); + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + result += sizeof(u64); + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + result += sizeof(u64); + /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ + if (read_format & PERF_FORMAT_GROUP) { + sz = sample->read.group.nr * + sizeof(struct sample_read_value); + result += sz; + } else { + result += sizeof(u64); + } + } + + if (type & PERF_SAMPLE_CALLCHAIN) { + sz = (sample->callchain->nr + 1) * sizeof(u64); + result += sz; + } + + if (type & PERF_SAMPLE_RAW) { + result += sizeof(u32); + result += sample->raw_size; + } + + if (type & PERF_SAMPLE_BRANCH_STACK) { + sz = sample->branch_stack->nr * sizeof(struct branch_entry); + sz += sizeof(u64); + result += sz; + } + + if (type & PERF_SAMPLE_REGS_USER) { + if (sample->user_regs.abi) { + result += sizeof(u64); + sz = hweight64(sample->user_regs.mask) * sizeof(u64); + result += sz; + } else { + result += sizeof(u64); + } + } + + if (type & PERF_SAMPLE_STACK_USER) { + sz = sample->user_stack.size; + result += sizeof(u64); + if (sz) { + result += sz; + result += sizeof(u64); + } + } + + if (type & PERF_SAMPLE_WEIGHT) + result += sizeof(u64); + + if (type & PERF_SAMPLE_DATA_SRC) + result += sizeof(u64); + + if (type & PERF_SAMPLE_TRANSACTION) + result += sizeof(u64); + + if (type & PERF_SAMPLE_REGS_INTR) { + if (sample->intr_regs.abi) { + result += sizeof(u64); + sz = hweight64(sample->intr_regs.mask) * sizeof(u64); + result += sz; + } else { + result += sizeof(u64); + } + } + + if (type & PERF_SAMPLE_PHYS_ADDR) + result += sizeof(u64); + + return result; +} + +int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, + const struct perf_sample *sample) +{ + __u64 *array; + size_t sz; + /* + * used for cross-endian analysis. See git commit 65014ab3 + * for why this goofiness is needed. + */ + union u64_swap u; + + array = event->sample.array; + + if (type & PERF_SAMPLE_IDENTIFIER) { + *array = sample->id; + array++; + } + + if (type & PERF_SAMPLE_IP) { + *array = sample->ip; + array++; + } + + if (type & PERF_SAMPLE_TID) { + u.val32[0] = sample->pid; + u.val32[1] = sample->tid; + *array = u.val64; + array++; + } + + if (type & PERF_SAMPLE_TIME) { + *array = sample->time; + array++; + } + + if (type & PERF_SAMPLE_ADDR) { + *array = sample->addr; + array++; + } + + if (type & PERF_SAMPLE_ID) { + *array = sample->id; + array++; + } + + if (type & PERF_SAMPLE_STREAM_ID) { + *array = sample->stream_id; + array++; + } + + if (type & PERF_SAMPLE_CPU) { + u.val32[0] = sample->cpu; + u.val32[1] = 0; + *array = u.val64; + array++; + } + + if (type & PERF_SAMPLE_PERIOD) { + *array = sample->period; + array++; + } + + if (type & PERF_SAMPLE_READ) { + if (read_format & PERF_FORMAT_GROUP) + *array = sample->read.group.nr; + else + *array = sample->read.one.value; + array++; + + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { + *array = sample->read.time_enabled; + array++; + } + + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { + *array = sample->read.time_running; + array++; + } + + /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */ + if (read_format & PERF_FORMAT_GROUP) { + sz = sample->read.group.nr * + sizeof(struct sample_read_value); + memcpy(array, sample->read.group.values, sz); + array = (void *)array + sz; + } else { + *array = sample->read.one.id; + array++; + } + } + + if (type & PERF_SAMPLE_CALLCHAIN) { + sz = (sample->callchain->nr + 1) * sizeof(u64); + memcpy(array, sample->callchain, sz); + array = (void *)array + sz; + } + + if (type & PERF_SAMPLE_RAW) { + u.val32[0] = sample->raw_size; + *array = u.val64; + array = (void *)array + sizeof(u32); + + memcpy(array, sample->raw_data, sample->raw_size); + array = (void *)array + sample->raw_size; + } + + if (type & PERF_SAMPLE_BRANCH_STACK) { + sz = sample->branch_stack->nr * sizeof(struct branch_entry); + sz += sizeof(u64); + memcpy(array, sample->branch_stack, sz); + array = (void *)array + sz; + } + + if (type & PERF_SAMPLE_REGS_USER) { + if (sample->user_regs.abi) { + *array++ = sample->user_regs.abi; + sz = hweight64(sample->user_regs.mask) * sizeof(u64); + memcpy(array, sample->user_regs.regs, sz); + array = (void *)array + sz; + } else { + *array++ = 0; + } + } + + if (type & PERF_SAMPLE_STACK_USER) { + sz = sample->user_stack.size; + *array++ = sz; + if (sz) { + memcpy(array, sample->user_stack.data, sz); + array = (void *)array + sz; + *array++ = sz; + } + } + + if (type & PERF_SAMPLE_WEIGHT) { + *array = sample->weight; + array++; + } + + if (type & PERF_SAMPLE_DATA_SRC) { + *array = sample->data_src; + array++; + } + + if (type & PERF_SAMPLE_TRANSACTION) { + *array = sample->transaction; + array++; + } + + if (type & PERF_SAMPLE_REGS_INTR) { + if (sample->intr_regs.abi) { + *array++ = sample->intr_regs.abi; + sz = hweight64(sample->intr_regs.mask) * sizeof(u64); + memcpy(array, sample->intr_regs.regs, sz); + array = (void *)array + sz; + } else { + *array++ = 0; + } + } + + if (type & PERF_SAMPLE_PHYS_ADDR) { + *array = sample->phys_addr; + array++; + } + + return 0; +} + +int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, + struct evlist *evlist, struct machine *machine) +{ + union perf_event *ev; + struct evsel *evsel; + size_t nr = 0, i = 0, sz, max_nr, n; + int err; + + pr_debug2("Synthesizing id index\n"); + + max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / + sizeof(struct id_index_entry); + + evlist__for_each_entry(evlist, evsel) + nr += evsel->core.ids; + + n = nr > max_nr ? max_nr : nr; + sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); + ev = zalloc(sz); + if (!ev) + return -ENOMEM; + + ev->id_index.header.type = PERF_RECORD_ID_INDEX; + ev->id_index.header.size = sz; + ev->id_index.nr = n; + + evlist__for_each_entry(evlist, evsel) { + u32 j; + + for (j = 0; j < evsel->core.ids; j++) { + struct id_index_entry *e; + struct perf_sample_id *sid; + + if (i >= n) { + err = process(tool, ev, NULL, machine); + if (err) + goto out_err; + nr -= n; + i = 0; + } + + e = &ev->id_index.entries[i++]; + + e->id = evsel->core.id[j]; + + sid = perf_evlist__id2sid(evlist, e->id); + if (!sid) { + free(ev); + return -ENOENT; + } + + e->idx = sid->idx; + e->cpu = sid->cpu; + e->tid = sid->tid; + } + } + + sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); + ev->id_index.header.size = sz; + ev->id_index.nr = nr; + + err = process(tool, ev, NULL, machine); +out_err: + free(ev); + + return err; +} + +int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, + struct target *target, struct perf_thread_map *threads, + perf_event__handler_t process, bool data_mmap, + unsigned int nr_threads_synthesize) +{ + if (target__has_task(target)) + return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap); + else if (target__has_cpu(target)) + return perf_event__synthesize_threads(tool, process, + machine, data_mmap, + nr_threads_synthesize); + /* command specified */ + return 0; +} + +int machine__synthesize_threads(struct machine *machine, struct target *target, + struct perf_thread_map *threads, bool data_mmap, + unsigned int nr_threads_synthesize) +{ + return __machine__synthesize_threads(machine, NULL, target, threads, + perf_event__process, data_mmap, + nr_threads_synthesize); +} + +static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id) +{ + struct perf_record_event_update *ev; + + size += sizeof(*ev); + size = PERF_ALIGN(size, sizeof(u64)); + + ev = zalloc(size); + if (ev) { + ev->header.type = PERF_RECORD_EVENT_UPDATE; + ev->header.size = (u16)size; + ev->type = type; + ev->id = id; + } + return ev; +} + +int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, + perf_event__handler_t process) +{ + size_t size = strlen(evsel->unit); + struct perf_record_event_update *ev; + int err; + + ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]); + if (ev == NULL) + return -ENOMEM; + + strlcpy(ev->data, evsel->unit, size + 1); + err = process(tool, (union perf_event *)ev, NULL, NULL); + free(ev); + return err; +} + +int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, + perf_event__handler_t process) +{ + struct perf_record_event_update *ev; + struct perf_record_event_update_scale *ev_data; + int err; + + ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]); + if (ev == NULL) + return -ENOMEM; + + ev_data = (struct perf_record_event_update_scale *)ev->data; + ev_data->scale = evsel->scale; + err = process(tool, (union perf_event *)ev, NULL, NULL); + free(ev); + return err; +} + +int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, + perf_event__handler_t process) +{ + struct perf_record_event_update *ev; + size_t len = strlen(evsel->name); + int err; + + ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]); + if (ev == NULL) + return -ENOMEM; + + strlcpy(ev->data, evsel->name, len + 1); + err = process(tool, (union perf_event *)ev, NULL, NULL); + free(ev); + return err; +} + +int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, + perf_event__handler_t process) +{ + size_t size = sizeof(struct perf_record_event_update); + struct perf_record_event_update *ev; + int max, err; + u16 type; + + if (!evsel->core.own_cpus) + return 0; + + ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); + if (!ev) + return -ENOMEM; + + ev->header.type = PERF_RECORD_EVENT_UPDATE; + ev->header.size = (u16)size; + ev->type = PERF_EVENT_UPDATE__CPUS; + ev->id = evsel->core.id[0]; + + cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, + evsel->core.own_cpus, type, max); + + err = process(tool, (union perf_event *)ev, NULL, NULL); + free(ev); + return err; +} + +int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, + perf_event__handler_t process) +{ + struct evsel *evsel; + int err = 0; + + evlist__for_each_entry(evlist, evsel) { + err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids, + evsel->core.id, process); + if (err) { + pr_debug("failed to create perf header attribute\n"); + return err; + } + } + + return err; +} + +static bool has_unit(struct evsel *evsel) +{ + return evsel->unit && *evsel->unit; +} + +static bool has_scale(struct evsel *evsel) +{ + return evsel->scale != 1; +} + +int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, + perf_event__handler_t process, bool is_pipe) +{ + struct evsel *evsel; + int err; + + /* + * Synthesize other events stuff not carried within + * attr event - unit, scale, name + */ + evlist__for_each_entry(evsel_list, evsel) { + if (!evsel->supported) + continue; + + /* + * Synthesize unit and scale only if it's defined. + */ + if (has_unit(evsel)) { + err = perf_event__synthesize_event_update_unit(tool, evsel, process); + if (err < 0) { + pr_err("Couldn't synthesize evsel unit.\n"); + return err; + } + } + + if (has_scale(evsel)) { + err = perf_event__synthesize_event_update_scale(tool, evsel, process); + if (err < 0) { + pr_err("Couldn't synthesize evsel evsel.\n"); + return err; + } + } + + if (evsel->core.own_cpus) { + err = perf_event__synthesize_event_update_cpus(tool, evsel, process); + if (err < 0) { + pr_err("Couldn't synthesize evsel cpus.\n"); + return err; + } + } + + /* + * Name is needed only for pipe output, + * perf.data carries event names. + */ + if (is_pipe) { + err = perf_event__synthesize_event_update_name(tool, evsel, process); + if (err < 0) { + pr_err("Couldn't synthesize evsel name.\n"); + return err; + } + } + } + return 0; +} + +int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, + u32 ids, u64 *id, perf_event__handler_t process) +{ + union perf_event *ev; + size_t size; + int err; + + size = sizeof(struct perf_event_attr); + size = PERF_ALIGN(size, sizeof(u64)); + size += sizeof(struct perf_event_header); + size += ids * sizeof(u64); + + ev = zalloc(size); + + if (ev == NULL) + return -ENOMEM; + + ev->attr.attr = *attr; + memcpy(ev->attr.id, id, ids * sizeof(u64)); + + ev->attr.header.type = PERF_RECORD_HEADER_ATTR; + ev->attr.header.size = (u16)size; + + if (ev->attr.header.size == size) + err = process(tool, ev, NULL, NULL); + else + err = -E2BIG; + + free(ev); + + return err; +} + +int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, + perf_event__handler_t process) +{ + union perf_event ev; + struct tracing_data *tdata; + ssize_t size = 0, aligned_size = 0, padding; + struct feat_fd ff; + + /* + * We are going to store the size of the data followed + * by the data contents. Since the fd descriptor is a pipe, + * we cannot seek back to store the size of the data once + * we know it. Instead we: + * + * - write the tracing data to the temp file + * - get/write the data size to pipe + * - write the tracing data from the temp file + * to the pipe + */ + tdata = tracing_data_get(&evlist->core.entries, fd, true); + if (!tdata) + return -1; + + memset(&ev, 0, sizeof(ev)); + + ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; + size = tdata->size; + aligned_size = PERF_ALIGN(size, sizeof(u64)); + padding = aligned_size - size; + ev.tracing_data.header.size = sizeof(ev.tracing_data); + ev.tracing_data.size = aligned_size; + + process(tool, &ev, NULL, NULL); + + /* + * The put function will copy all the tracing data + * stored in temp file to the pipe. + */ + tracing_data_put(tdata); + + ff = (struct feat_fd){ .fd = fd }; + if (write_padded(&ff, NULL, 0, padding)) + return -1; + + return aligned_size; +} + +int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, + perf_event__handler_t process, struct machine *machine) +{ + union perf_event ev; + size_t len; + + if (!pos->hit) + return 0; + + memset(&ev, 0, sizeof(ev)); + + len = pos->long_name_len + 1; + len = PERF_ALIGN(len, NAME_ALIGN); + memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); + ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; + ev.build_id.header.misc = misc; + ev.build_id.pid = machine->pid; + ev.build_id.header.size = sizeof(ev.build_id) + len; + memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); + + return process(tool, &ev, NULL, machine); +} + +int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, + struct evlist *evlist, perf_event__handler_t process, bool attrs) +{ + int err; + + if (attrs) { + err = perf_event__synthesize_attrs(tool, evlist, process); + if (err < 0) { + pr_err("Couldn't synthesize attrs.\n"); + return err; + } + } + + err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); + err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); + if (err < 0) { + pr_err("Couldn't synthesize thread map.\n"); + return err; + } + + err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); + if (err < 0) { + pr_err("Couldn't synthesize thread map.\n"); + return err; + } + + err = perf_event__synthesize_stat_config(tool, config, process, NULL); + if (err < 0) { + pr_err("Couldn't synthesize config.\n"); + return err; + } + + return 0; +} + +int __weak perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, + struct perf_tool *tool __maybe_unused, + perf_event__handler_t process __maybe_unused, + struct machine *machine __maybe_unused) +{ + return 0; +} + +extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; + +int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, + struct evlist *evlist, perf_event__handler_t process) +{ + struct perf_header *header = &session->header; + struct perf_record_header_feature *fe; + struct feat_fd ff; + size_t sz, sz_hdr; + int feat, ret; + + sz_hdr = sizeof(fe->header); + sz = sizeof(union perf_event); + /* get a nice alignment */ + sz = PERF_ALIGN(sz, page_size); + + memset(&ff, 0, sizeof(ff)); + + ff.buf = malloc(sz); + if (!ff.buf) + return -ENOMEM; + + ff.size = sz - sz_hdr; + ff.ph = &session->header; + + for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { + if (!feat_ops[feat].synthesize) { + pr_debug("No record header feature for header :%d\n", feat); + continue; + } + + ff.offset = sizeof(*fe); + + ret = feat_ops[feat].write(&ff, evlist); + if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { + pr_debug("Error writing feature\n"); + continue; + } + /* ff.buf may have changed due to realloc in do_write() */ + fe = ff.buf; + memset(fe, 0, sizeof(*fe)); + + fe->feat_id = feat; + fe->header.type = PERF_RECORD_HEADER_FEATURE; + fe->header.size = ff.offset; + + ret = process(tool, ff.buf, NULL, NULL); + if (ret) { + free(ff.buf); + return ret; + } + } + + /* Send HEADER_LAST_FEATURE mark. */ + fe = ff.buf; + fe->feat_id = HEADER_LAST_FEATURE; + fe->header.type = PERF_RECORD_HEADER_FEATURE; + fe->header.size = sizeof(*fe); + + ret = process(tool, ff.buf, NULL, NULL); + + free(ff.buf); + return ret; +} diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h new file mode 100644 index 000000000000..baead0cdc381 --- /dev/null +++ b/tools/perf/util/synthetic-events.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_SYNTHETIC_EVENTS_H +#define __PERF_SYNTHETIC_EVENTS_H + +#include <stdbool.h> +#include <sys/types.h> // pid_t +#include <linux/compiler.h> +#include <linux/types.h> + +struct auxtrace_record; +struct dso; +struct evlist; +struct evsel; +struct machine; +struct perf_counts_values; +struct perf_cpu_map; +struct perf_event_attr; +struct perf_event_mmap_page; +struct perf_sample; +struct perf_session; +struct perf_stat_config; +struct perf_thread_map; +struct perf_tool; +struct record_opts; +struct target; + +union perf_event; + +typedef int (*perf_event__handler_t)(struct perf_tool *tool, union perf_event *event, + struct perf_sample *sample, struct machine *machine); + +int perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process); +int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u32 ids, u64 *id, perf_event__handler_t process); +int perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_cpu_map(struct perf_tool *tool, struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel, perf_event__handler_t process); +int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list, perf_event__handler_t process, bool is_pipe); +int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, struct evlist *evlist, perf_event__handler_t process); +int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine); +int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_mmap_events(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine, bool mmap_data); +int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_namespaces(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, const struct perf_sample *sample); +int perf_event__synthesize_stat_config(struct perf_tool *tool, struct perf_stat_config *config, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process, bool attrs); +int perf_event__synthesize_stat_round(struct perf_tool *tool, u64 time, u64 type, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_stat(struct perf_tool *tool, u32 cpu, u32 thread, u64 id, struct perf_counts_values *count, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_thread_map2(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine); +int perf_event__synthesize_thread_map(struct perf_tool *tool, struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool mmap_data); +int perf_event__synthesize_threads(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine, bool mmap_data, unsigned int nr_threads_synthesize); +int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist, perf_event__handler_t process); +int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); +pid_t perf_event__synthesize_comm(struct perf_tool *tool, union perf_event *event, pid_t pid, perf_event__handler_t process, struct machine *machine); + +int perf_tool__process_synth_event(struct perf_tool *tool, union perf_event *event, struct machine *machine, perf_event__handler_t process); + +size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format); + +int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, + struct target *target, struct perf_thread_map *threads, + perf_event__handler_t process, bool data_mmap, + unsigned int nr_threads_synthesize); +int machine__synthesize_threads(struct machine *machine, struct target *target, + struct perf_thread_map *threads, bool data_mmap, + unsigned int nr_threads_synthesize); + +#ifdef HAVE_AUXTRACE_SUPPORT +int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, struct perf_tool *tool, + struct perf_session *session, perf_event__handler_t process); + +#else // HAVE_AUXTRACE_SUPPORT + +#include <errno.h> + +static inline int +perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr __maybe_unused, + struct perf_tool *tool __maybe_unused, + struct perf_session *session __maybe_unused, + perf_event__handler_t process __maybe_unused) +{ + return -EINVAL; +} +#endif // HAVE_AUXTRACE_SUPPORT + +#ifdef HAVE_LIBBPF_SUPPORT +int perf_event__synthesize_bpf_events(struct perf_session *session, perf_event__handler_t process, + struct machine *machine, struct record_opts *opts); +#else // HAVE_LIBBPF_SUPPORT +static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused, + perf_event__handler_t process __maybe_unused, + struct machine *machine __maybe_unused, + struct record_opts *opts __maybe_unused) +{ + return 0; +} +#endif // HAVE_LIBBPF_SUPPORT + +#endif // __PERF_SYNTHETIC_EVENTS_H diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 565f7aef7e6c..a3db13dea937 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -6,8 +6,6 @@ */ #include "target.h" -#include "util.h" -#include "debug.h" #include <pwd.h> #include <stdio.h> diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 51fb574998bb..3dce2de9d005 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -5,7 +5,6 @@ * Refactored from builtin-top.c, see that files for further copyright notes. */ -#include "cpumap.h" #include "event.h" #include "evlist.h" #include "evsel.h" @@ -72,7 +71,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) } if (top->evlist->core.nr_entries == 1) { - struct evsel *first = perf_evlist__first(top->evlist); + struct evsel *first = evlist__first(top->evlist); ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", (uint64_t)first->core.attr.sample_period, opts->freq ? "Hz" : ""); diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index d63d542b2cde..086e98ff42a3 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -2,7 +2,6 @@ /* * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com> */ -#include "util.h" #include <dirent.h> #include <mntent.h> #include <stdio.h> @@ -19,6 +18,7 @@ #include <linux/list.h> #include <linux/kernel.h> #include <linux/zalloc.h> +#include <internal/lib.h> // page_size #include "trace-event.h" #include <api/fs/tracing_path.h> diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index b6c0db068be0..8593d3c200c6 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -15,7 +15,6 @@ #include <unistd.h> #include <errno.h> -#include "util.h" #include "trace-event.h" #include "debug.h" diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 01b9d89bf5bf..b3ee651e3d91 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -14,7 +14,6 @@ #include <api/fs/fs.h> #include "trace-event.h" #include "machine.h" -#include "util.h" /* * global trace_event object used by trace_event__tp_format diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h index e0c3af34ac8d..3c5a632ee57c 100644 --- a/tools/perf/util/tsc.h +++ b/tools/perf/util/tsc.h @@ -4,13 +4,12 @@ #include <linux/types.h> -#include "event.h" - struct perf_tsc_conversion { u16 time_shift; u32 time_mult; u64 time_zero; }; + struct perf_event_mmap_page; int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, @@ -20,13 +19,4 @@ u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); u64 rdtsc(void); -struct perf_event_mmap_page; -struct perf_tool; -struct machine; - -int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, - struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); - -#endif +#endif // __PERF_TSC_H diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 9ece188ae48a..15f6e46d7124 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -17,7 +17,6 @@ #include "event.h" #include "perf_regs.h" #include "callchain.h" -#include "util.h" static char *debuginfo_path; diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index ebdbb056510c..1800887b2255 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -37,7 +37,6 @@ #include "unwind.h" #include "map.h" #include "symbol.h" -#include "util.h" #include "debug.h" #include "asm/bug.h" #include "dso.h" diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 3949a60b00ae..196438ee4c9d 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -8,7 +8,6 @@ * Copyright (C) Linus Torvalds, 2005 */ #include "util.h" -#include "debug.h" #include <stdio.h> #include <stdlib.h> #include <linux/compiler.h> diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 32322a20a68b..5eda6e19c947 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -2,9 +2,7 @@ #include "util.h" #include "debug.h" #include "event.h" -#include "namespaces.h" #include <api/fs/fs.h> -#include <sys/mman.h> #include <sys/stat.h> #include <sys/utsname.h> #include <dirent.h> @@ -41,8 +39,6 @@ void perf_set_multithreaded(void) perf_singlethreaded = false; } -unsigned int page_size; - int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; @@ -234,138 +230,6 @@ out: return list; } -static int slow_copyfile(const char *from, const char *to, struct nsinfo *nsi) -{ - int err = -1; - char *line = NULL; - size_t n; - FILE *from_fp, *to_fp; - struct nscookie nsc; - - nsinfo__mountns_enter(nsi, &nsc); - from_fp = fopen(from, "r"); - nsinfo__mountns_exit(&nsc); - if (from_fp == NULL) - goto out; - - to_fp = fopen(to, "w"); - if (to_fp == NULL) - goto out_fclose_from; - - while (getline(&line, &n, from_fp) > 0) - if (fputs(line, to_fp) == EOF) - goto out_fclose_to; - err = 0; -out_fclose_to: - fclose(to_fp); - free(line); -out_fclose_from: - fclose(from_fp); -out: - return err; -} - -int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) -{ - void *ptr; - loff_t pgoff; - - pgoff = off_in & ~(page_size - 1); - off_in -= pgoff; - - ptr = mmap(NULL, off_in + size, PROT_READ, MAP_PRIVATE, ifd, pgoff); - if (ptr == MAP_FAILED) - return -1; - - while (size) { - ssize_t ret = pwrite(ofd, ptr + off_in, size, off_out); - if (ret < 0 && errno == EINTR) - continue; - if (ret <= 0) - break; - - size -= ret; - off_in += ret; - off_out += ret; - } - munmap(ptr, off_in + size); - - return size ? -1 : 0; -} - -static int copyfile_mode_ns(const char *from, const char *to, mode_t mode, - struct nsinfo *nsi) -{ - int fromfd, tofd; - struct stat st; - int err; - char *tmp = NULL, *ptr = NULL; - struct nscookie nsc; - - nsinfo__mountns_enter(nsi, &nsc); - err = stat(from, &st); - nsinfo__mountns_exit(&nsc); - if (err) - goto out; - err = -1; - - /* extra 'x' at the end is to reserve space for '.' */ - if (asprintf(&tmp, "%s.XXXXXXx", to) < 0) { - tmp = NULL; - goto out; - } - ptr = strrchr(tmp, '/'); - if (!ptr) - goto out; - ptr = memmove(ptr + 1, ptr, strlen(ptr) - 1); - *ptr = '.'; - - tofd = mkstemp(tmp); - if (tofd < 0) - goto out; - - if (fchmod(tofd, mode)) - goto out_close_to; - - if (st.st_size == 0) { /* /proc? do it slowly... */ - err = slow_copyfile(from, tmp, nsi); - goto out_close_to; - } - - nsinfo__mountns_enter(nsi, &nsc); - fromfd = open(from, O_RDONLY); - nsinfo__mountns_exit(&nsc); - if (fromfd < 0) - goto out_close_to; - - err = copyfile_offset(fromfd, 0, tofd, 0, st.st_size); - - close(fromfd); -out_close_to: - close(tofd); - if (!err) - err = link(tmp, to); - unlink(tmp); -out: - free(tmp); - return err; -} - -int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi) -{ - return copyfile_mode_ns(from, to, 0755, nsi); -} - -int copyfile_mode(const char *from, const char *to, mode_t mode) -{ - return copyfile_mode_ns(from, to, mode, NULL); -} - -int copyfile(const char *from, const char *to) -{ - return copyfile_mode(from, to, 0755); -} - size_t hex_width(u64 v) { size_t n = 1; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 45a5c6f20197..9969b8b46f7c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -11,14 +11,12 @@ #include <stddef.h> #include <linux/compiler.h> #include <sys/types.h> -#include <internal/lib.h> /* General helper functions */ void usage(const char *err) __noreturn; void die(const char *err, ...) __noreturn __printf(1, 2); struct dirent; -struct nsinfo; struct strlist; int mkdir_p(char *path, mode_t mode); @@ -26,15 +24,9 @@ int rm_rf(const char *path); int rm_rf_perf_data(const char *path); struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); bool lsdir_no_dot_filter(const char *name, struct dirent *d); -int copyfile(const char *from, const char *to); -int copyfile_mode(const char *from, const char *to, mode_t mode); -int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); -int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size); size_t hex_width(u64 v); -extern unsigned int page_size; - int sysctl__max_stack(void); int fetch_kernel_version(unsigned int *puint, diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index e5e6599603f4..ba4b4395f35d 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -11,7 +11,7 @@ #include "vdso.h" #include "dso.h" -#include "util.h" +#include <internal/lib.h> #include "map.h" #include "symbol.h" #include "machine.h" diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c index 59d456f716e9..78d2297c1b67 100644 --- a/tools/perf/util/zlib.c +++ b/tools/perf/util/zlib.c @@ -7,11 +7,9 @@ #include <sys/mman.h> #include <zlib.h> #include <linux/compiler.h> +#include <internal/lib.h> #include "util/compress.h" -#include "util/util.h" -#include "util/debug.h" - #define CHUNK_SIZE 16384 diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 59753b3917bb..2a9890c8395a 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -38,6 +38,7 @@ static int fact_avx = 0xFF; static unsigned long long fact_trl; static int out_format_json; static int cmd_help; +static int force_online_offline; /* clos related */ static int current_clos = -1; @@ -138,14 +139,14 @@ int out_format_is_json(void) int get_physical_package_id(int cpu) { return parse_int_file( - 1, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", + 0, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); } int get_physical_core_id(int cpu) { return parse_int_file( - 1, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); + 0, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); } int get_physical_die_id(int cpu) @@ -165,6 +166,26 @@ int get_topo_max_cpus(void) return topo_max_cpus; } +static void set_cpu_online_offline(int cpu, int state) +{ + char buffer[128]; + int fd; + + snprintf(buffer, sizeof(buffer), + "/sys/devices/system/cpu/cpu%d/online", cpu); + + fd = open(buffer, O_WRONLY); + if (fd < 0) + err(-1, "%s open failed", buffer); + + if (state) + write(fd, "1\n", 2); + else + write(fd, "0\n", 2); + + close(fd); +} + #define MAX_PACKAGE_COUNT 8 #define MAX_DIE_PER_PACKAGE 2 static void for_each_online_package_in_set(void (*callback)(int, void *, void *, @@ -402,6 +423,9 @@ void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask, int j; for (j = 0; j < topo_max_cpus; ++j) { + if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask)) + continue; + if (cpu_map[j].pkg_id == pkg_id && cpu_map[j].die_id == die_id && cpu_map[j].punit_cpu_core == i) { @@ -484,7 +508,7 @@ int isst_send_mbox_command(unsigned int cpu, unsigned char command, int write = 0; int clos_id, core_id, ret = 0; - debug_printf("CLOS %d\n", cpu); + debug_printf("CPU %d\n", cpu); if (parameter & BIT(MBOX_CMD_WRITE_BIT)) { value = req_data; @@ -649,8 +673,8 @@ static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3, if (ret) perror("get_tdp_*"); else - isst_display_result(cpu, outf, "perf-profile", (char *)arg3, - *(unsigned int *)arg4); + isst_ctdp_display_core_info(cpu, outf, arg3, + *(unsigned int *)arg4); } #define _get_tdp_level(desc, suffix, object, help) \ @@ -733,9 +757,34 @@ static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, ret = isst_set_tdp_level(cpu, tdp_level); if (ret) perror("set_tdp_level_for_cpu"); - else + else { isst_display_result(cpu, outf, "perf-profile", "set_tdp_level", ret); + if (force_online_offline) { + struct isst_pkg_ctdp_level_info ctdp_level; + int pkg_id = get_physical_package_id(cpu); + int die_id = get_physical_die_id(cpu); + + fprintf(stderr, "Option is set to online/offline\n"); + ctdp_level.core_cpumask_size = + alloc_cpu_set(&ctdp_level.core_cpumask); + isst_get_coremask_info(cpu, tdp_level, &ctdp_level); + if (ctdp_level.cpu_count) { + int i, max_cpus = get_topo_max_cpus(); + for (i = 0; i < max_cpus; ++i) { + if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i)) + continue; + if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) { + fprintf(stderr, "online cpu %d\n", i); + set_cpu_online_offline(i, 1); + } else { + fprintf(stderr, "offline cpu %d\n", i); + set_cpu_online_offline(i, 0); + } + } + } + } + } } static void set_tdp_level(void) @@ -744,6 +793,8 @@ static void set_tdp_level(void) fprintf(stderr, "Set Config TDP level\n"); fprintf(stderr, "\t Arguments: -l|--level : Specify tdp level\n"); + fprintf(stderr, + "\t Optional Arguments: -o | online : online/offline for the tdp level\n"); exit(0); } @@ -1082,6 +1133,40 @@ static void dump_clos_config(void) isst_ctdp_display_information_end(outf); } +static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, + void *arg4) +{ + int enable, ret, prio_type; + + ret = isst_clos_get_clos_information(cpu, &enable, &prio_type); + if (ret) + perror("isst_clos_get_info"); + else + isst_clos_display_clos_information(cpu, outf, enable, prio_type); +} + +static void dump_clos_info(void) +{ + if (cmd_help) { + fprintf(stderr, + "Print Intel Speed Select Technology core power information\n"); + fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n"); + exit(0); + } + + if (!max_target_cpus) { + fprintf(stderr, + "Invalid target cpu. Specify with [-c|--cpu]\n"); + exit(0); + } + + isst_ctdp_display_information_start(outf); + for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL, + NULL, NULL, NULL); + isst_ctdp_display_information_end(outf); + +} + static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, void *arg4) { @@ -1198,7 +1283,7 @@ static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3, if (ret) perror("isst_clos_get_assoc_status"); else - isst_display_result(cpu, outf, "core-power", "get-assoc", clos); + isst_clos_display_assoc_information(cpu, outf, clos); } static void get_clos_assoc(void) @@ -1208,13 +1293,17 @@ static void get_clos_assoc(void) fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n"); exit(0); } - if (max_target_cpus) - for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL, - NULL, NULL, NULL); - else { + + if (!max_target_cpus) { fprintf(stderr, "Invalid target cpu. Specify with [-c|--cpu]\n"); + exit(0); } + + isst_ctdp_display_information_start(outf); + for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL, + NULL, NULL, NULL); + isst_ctdp_display_information_end(outf); } static struct process_cmd_struct isst_cmds[] = { @@ -1231,10 +1320,11 @@ static struct process_cmd_struct isst_cmds[] = { { "turbo-freq", "info", dump_fact_config }, { "turbo-freq", "enable", set_fact_enable }, { "turbo-freq", "disable", set_fact_disable }, - { "core-power", "info", dump_clos_config }, + { "core-power", "info", dump_clos_info }, { "core-power", "enable", set_clos_enable }, { "core-power", "disable", set_clos_disable }, { "core-power", "config", set_clos_config }, + { "core-power", "get-config", dump_clos_config }, { "core-power", "assoc", set_clos_assoc }, { "core-power", "get-assoc", get_clos_assoc }, { NULL, NULL, NULL } @@ -1316,6 +1406,7 @@ static void parse_cmd_args(int argc, int start, char **argv) static struct option long_options[] = { { "bucket", required_argument, 0, 'b' }, { "level", required_argument, 0, 'l' }, + { "online", required_argument, 0, 'o' }, { "trl-type", required_argument, 0, 'r' }, { "trl", required_argument, 0, 't' }, { "help", no_argument, 0, 'h' }, @@ -1332,7 +1423,7 @@ static void parse_cmd_args(int argc, int start, char **argv) option_index = start; optind = start + 1; - while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:h", + while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:ho", long_options, &option_index)) != -1) { switch (opt) { case 'b': @@ -1344,6 +1435,9 @@ static void parse_cmd_args(int argc, int start, char **argv) case 'l': tdp_level = atoi(optarg); break; + case 'o': + force_online_offline = 1; + break; case 't': sscanf(optarg, "0x%llx", &fact_trl); break; @@ -1362,7 +1456,6 @@ static void parse_cmd_args(int argc, int start, char **argv) /* CLOS related */ case 'c': current_clos = atoi(optarg); - printf("clos %d\n", current_clos); break; case 'd': clos_desired = atoi(optarg); @@ -1433,6 +1526,7 @@ static void core_power_help(void) printf("\tenable\n"); printf("\tdisable\n"); printf("\tconfig\n"); + printf("\tget-config\n"); printf("\tassoc\n"); printf("\tget-assoc\n"); } diff --git a/tools/power/x86/intel-speed-select/isst-core.c b/tools/power/x86/intel-speed-select/isst-core.c index 0bf341ad9697..6dee5332c9d3 100644 --- a/tools/power/x86/intel-speed-select/isst-core.c +++ b/tools/power/x86/intel-speed-select/isst-core.c @@ -619,6 +619,31 @@ int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev) return 0; } +int isst_clos_get_clos_information(int cpu, int *enable, int *type) +{ + unsigned int resp; + int ret; + + ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0, + &resp); + if (ret) + return ret; + + debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", cpu, resp); + + if (resp & BIT(1)) + *enable = 1; + else + *enable = 0; + + if (resp & BIT(2)) + *type = 1; + else + *type = 0; + + return 0; +} + int isst_pm_qos_config(int cpu, int enable_clos, int priority_type) { unsigned int req, resp; diff --git a/tools/power/x86/intel-speed-select/isst-display.c b/tools/power/x86/intel-speed-select/isst-display.c index df4aa99c4e92..40346d534f78 100644 --- a/tools/power/x86/intel-speed-select/isst-display.c +++ b/tools/power/x86/intel-speed-select/isst-display.c @@ -287,6 +287,26 @@ static void _isst_fact_display_information(int cpu, FILE *outf, int level, format_and_print(outf, base_level + 2, header, value); } +void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix, + unsigned int val) +{ + char header[256]; + char value[256]; + + snprintf(header, sizeof(header), "package-%d", + get_physical_package_id(cpu)); + format_and_print(outf, 1, header, NULL); + snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); + format_and_print(outf, 2, header, NULL); + snprintf(header, sizeof(header), "cpu-%d", cpu); + format_and_print(outf, 3, header, NULL); + + snprintf(value, sizeof(value), "%u", val); + format_and_print(outf, 4, prefix, value); + + format_and_print(outf, 1, NULL, NULL); +} + void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level, struct isst_pkg_ctdp *pkg_dev) { @@ -503,6 +523,57 @@ void isst_clos_display_information(int cpu, FILE *outf, int clos, format_and_print(outf, 1, NULL, NULL); } +void isst_clos_display_clos_information(int cpu, FILE *outf, + int clos_enable, int type) +{ + char header[256]; + char value[256]; + + snprintf(header, sizeof(header), "package-%d", + get_physical_package_id(cpu)); + format_and_print(outf, 1, header, NULL); + snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); + format_and_print(outf, 2, header, NULL); + snprintf(header, sizeof(header), "cpu-%d", cpu); + format_and_print(outf, 3, header, NULL); + + snprintf(header, sizeof(header), "core-power"); + format_and_print(outf, 4, header, NULL); + + snprintf(header, sizeof(header), "enable-status"); + snprintf(value, sizeof(value), "%d", clos_enable); + format_and_print(outf, 5, header, value); + + snprintf(header, sizeof(header), "priority-type"); + snprintf(value, sizeof(value), "%d", type); + format_and_print(outf, 5, header, value); + + format_and_print(outf, 1, NULL, NULL); +} + +void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos) +{ + char header[256]; + char value[256]; + + snprintf(header, sizeof(header), "package-%d", + get_physical_package_id(cpu)); + format_and_print(outf, 1, header, NULL); + snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); + format_and_print(outf, 2, header, NULL); + snprintf(header, sizeof(header), "cpu-%d", cpu); + format_and_print(outf, 3, header, NULL); + + snprintf(header, sizeof(header), "get-assoc"); + format_and_print(outf, 4, header, NULL); + + snprintf(header, sizeof(header), "clos"); + snprintf(value, sizeof(value), "%d", clos); + format_and_print(outf, 5, header, value); + + format_and_print(outf, 1, NULL, NULL); +} + void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd, int result) { diff --git a/tools/power/x86/intel-speed-select/isst.h b/tools/power/x86/intel-speed-select/isst.h index 2f7f62765eb6..d280b27d600d 100644 --- a/tools/power/x86/intel-speed-select/isst.h +++ b/tools/power/x86/intel-speed-select/isst.h @@ -187,12 +187,16 @@ extern int isst_send_msr_command(unsigned int cpu, unsigned int command, int write, unsigned long long *req_resp); extern int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev); +extern int isst_get_coremask_info(int cpu, int config_index, + struct isst_pkg_ctdp_level_info *ctdp_level); extern int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev); extern void isst_get_process_ctdp_complete(int cpu, struct isst_pkg_ctdp *pkg_dev); extern void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level, struct isst_pkg_ctdp *pkg_dev); +extern void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix, + unsigned int val); extern void isst_ctdp_display_information_start(FILE *outf); extern void isst_ctdp_display_information_end(FILE *outf); extern void isst_pbf_display_information(int cpu, FILE *outf, int level, @@ -223,10 +227,14 @@ extern int isst_clos_associate(int cpu, int clos); extern int isst_clos_get_assoc_status(int cpu, int *clos_id); extern void isst_clos_display_information(int cpu, FILE *outf, int clos, struct isst_clos_config *clos_config); - +extern void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos); extern int isst_read_reg(unsigned short reg, unsigned int *val); extern int isst_write_reg(int reg, unsigned int val); extern void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd, int result); + +extern int isst_clos_get_clos_information(int cpu, int *enable, int *type); +extern void isst_clos_display_clos_information(int cpu, FILE *outf, + int clos_enable, int type); #endif diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c index 2d4baf57822f..57bd27dedf1f 100644 --- a/tools/testing/nvdimm/dimm_devs.c +++ b/tools/testing/nvdimm/dimm_devs.c @@ -18,24 +18,13 @@ ssize_t security_show(struct device *dev, * For the test version we need to poll the "hardware" in order * to get the updated status for unlock testing. */ - nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); - nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); + nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); - switch (nvdimm->sec.state) { - case NVDIMM_SECURITY_DISABLED: + if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags)) return sprintf(buf, "disabled\n"); - case NVDIMM_SECURITY_UNLOCKED: + if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) return sprintf(buf, "unlocked\n"); - case NVDIMM_SECURITY_LOCKED: + if (test_bit(NVDIMM_SECURITY_LOCKED, &nvdimm->sec.flags)) return sprintf(buf, "locked\n"); - case NVDIMM_SECURITY_FROZEN: - return sprintf(buf, "frozen\n"); - case NVDIMM_SECURITY_OVERWRITE: - return sprintf(buf, "overwrite\n"); - default: - return -ENOTTY; - } - return -ENOTTY; } - diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index cd040b5abffe..3f55f2f99112 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c @@ -132,7 +132,6 @@ void *__wrap_devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap) if (!nfit_res) return devm_memremap_pages(dev, pgmap); - pgmap->dev = dev; if (!pgmap->ref) { if (pgmap->ops && (pgmap->ops->kill || pgmap->ops->cleanup)) return ERR_PTR(-EINVAL); diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 507e6f4cbb53..bf6422a6af7f 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -428,10 +428,9 @@ static int nd_intel_test_finish_query(struct nfit_test *t, dev_dbg(dev, "%s: still verifying\n", __func__); break; } - dev_dbg(dev, "%s: transition out verify\n", __func__); fw->state = FW_STATE_UPDATED; - /* we are going to fall through if it's "done" */ + /* fall through */ case FW_STATE_UPDATED: nd_cmd->status = 0; /* bogus test version */ diff --git a/tools/testing/selftests/.gitignore b/tools/testing/selftests/.gitignore index 8059ce834247..61df01cdf0b2 100644 --- a/tools/testing/selftests/.gitignore +++ b/tools/testing/selftests/.gitignore @@ -2,3 +2,5 @@ gpiogpio-event-mon gpiogpio-hammer gpioinclude/ gpiolsgpio +tpm2/SpaceTest.log +tpm2/*.pyc diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 25b43a8c2b15..c3feccb99ff5 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -126,9 +126,9 @@ endif # in the default INSTALL_HDR_PATH usr/include. khdr: ifeq (1,$(DEFAULT_INSTALL_HDR_PATH)) - make --no-builtin-rules ARCH=$(ARCH) -C $(top_srcdir) headers_install + $(MAKE) --no-builtin-rules ARCH=$(ARCH) -C $(top_srcdir) headers_install else - make --no-builtin-rules INSTALL_HDR_PATH=$$BUILD/usr \ + $(MAKE) --no-builtin-rules INSTALL_HDR_PATH=$$BUILD/usr \ ARCH=$(ARCH) -C $(top_srcdir) headers_install endif @@ -136,35 +136,35 @@ all: khdr @for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ mkdir $$BUILD_TARGET -p; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET;\ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET;\ done; run_tests: all @for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\ done; hotplug: @for TARGET in $(TARGETS_HOTPLUG); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET;\ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET;\ done; run_hotplug: hotplug @for TARGET in $(TARGETS_HOTPLUG); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET run_full_test;\ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_full_test;\ done; clean_hotplug: @for TARGET in $(TARGETS_HOTPLUG); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ done; run_pstore_crash: - make -C pstore run_crash + $(MAKE) -C pstore run_crash # Use $BUILD as the default install root. $BUILD points to the # right output location for the following cases: @@ -184,7 +184,7 @@ ifdef INSTALL_PATH install -m 744 kselftest/prefix.pl $(INSTALL_PATH)/kselftest/ @for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \ done; @# Ask all targets to emit their test scripts @@ -203,7 +203,7 @@ ifdef INSTALL_PATH echo "[ -w /dev/kmsg ] && echo \"kselftest: Running tests in $$TARGET\" >> /dev/kmsg" >> $(ALL_SCRIPT); \ echo "cd $$TARGET" >> $(ALL_SCRIPT); \ echo -n "run_many" >> $(ALL_SCRIPT); \ - make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ + $(MAKE) -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ echo "" >> $(ALL_SCRIPT); \ echo "cd \$$ROOT" >> $(ALL_SCRIPT); \ done; @@ -216,7 +216,7 @@ endif clean: @for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ done; .PHONY: khdr all run_tests hotplug run_hotplug clean_hotplug run_pstore_crash install clean diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile index a61b2e743e99..f9f79fb272f0 100644 --- a/tools/testing/selftests/arm64/Makefile +++ b/tools/testing/selftests/arm64/Makefile @@ -4,6 +4,7 @@ ARCH ?= $(shell uname -m 2>/dev/null || echo not) ifneq (,$(filter $(ARCH),aarch64 arm64)) +CFLAGS += -I../../../../usr/include/ TEST_GEN_PROGS := tags_test TEST_PROGS := run_tags_test.sh endif diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index 1d96c5f7e402..86986c4bba54 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions @@ -115,7 +115,7 @@ ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file command=$(echo "$2" | tr -d ^) echo "Test command: $command" echo > error_log - (! echo "$command" > "$3" ) 2> /dev/null + (! echo "$command" >> "$3" ) 2> /dev/null grep "$1: error:" -A 3 error_log N=$(tail -n 1 error_log | wc -c) # " Command: " and "^\n" => 13 diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc index 3fb70e01b1fe..3ff236719b6e 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_eventname.tc @@ -24,7 +24,21 @@ test -d events/kprobes2/event2 || exit_failure :;: "Add an event on dot function without name" ;: -FUNC=`grep -m 10 " [tT] .*\.isra\..*$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "` +find_dot_func() { + if [ ! -f available_filter_functions ]; then + grep -m 10 " [tT] .*\.isra\..*$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " " + return; + fi + + grep " [tT] .*\.isra\..*" /proc/kallsyms | cut -f 3 -d " " | while read f; do + if grep -s $f available_filter_functions; then + echo $f + break + fi + done +} + +FUNC=`find_dot_func | tail -n 1` [ "x" != "x$FUNC" ] || exit_unresolved echo "p $FUNC" > kprobe_events EVENT=`grep $FUNC kprobe_events | cut -f 1 -d " " | cut -f 2 -d:` diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc new file mode 100644 index 000000000000..44494bac86d1 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_multiprobe.tc @@ -0,0 +1,35 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Create/delete multiprobe on kprobe event + +[ -f kprobe_events ] || exit_unsupported + +grep -q "Create/append/" README || exit_unsupported + +# Choose 2 symbols for target +SYM1=_do_fork +SYM2=do_exit +EVENT_NAME=kprobes/testevent + +DEF1="p:$EVENT_NAME $SYM1" +DEF2="p:$EVENT_NAME $SYM2" + +:;: "Define an event which has 2 probes" ;: +echo $DEF1 >> kprobe_events +echo $DEF2 >> kprobe_events +cat kprobe_events | grep "$DEF1" +cat kprobe_events | grep "$DEF2" + +:;: "Remove the event by name (should remove both)" ;: +echo "-:$EVENT_NAME" >> kprobe_events +test `cat kprobe_events | wc -l` -eq 0 + +:;: "Remove just 1 event" ;: +echo $DEF1 >> kprobe_events +echo $DEF2 >> kprobe_events +echo "-:$EVENT_NAME $SYM1" >> kprobe_events +! cat kprobe_events | grep "$DEF1" +cat kprobe_events | grep "$DEF2" + +:;: "Appending different type must fail" ;: +! echo "$DEF1 \$stack" >> kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc index 29faaec942c6..8a4025e912cb 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_syntax_errors.tc @@ -41,6 +41,11 @@ check_error 'p vfs_read ^%none_reg' # BAD_REG_NAME check_error 'p vfs_read ^@12345678abcde' # BAD_MEM_ADDR check_error 'p vfs_read ^@+10' # FILE_ON_KPROBE +grep -q "imm-value" README && \ +check_error 'p vfs_read arg1=\^x' # BAD_IMM +grep -q "imm-string" README && \ +check_error 'p vfs_read arg1=\"abcd^' # IMMSTR_NO_CLOSE + check_error 'p vfs_read ^+0@0)' # DEREF_NEED_BRACE check_error 'p vfs_read ^+0ab1(@0)' # BAD_DEREF_OFFS check_error 'p vfs_read +0(+0(@0^)' # DEREF_OPEN_BRACE @@ -82,4 +87,15 @@ case $(uname -m) in ;; esac +# multiprobe errors +if grep -q "Create/append/" README && grep -q "imm-value" README; then +echo 'p:kprobes/testevent _do_fork' > kprobe_events +check_error '^r:kprobes/testevent do_exit' # DIFF_PROBE_TYPE +echo 'p:kprobes/testevent _do_fork abcd=\1' > kprobe_events +check_error 'p:kprobes/testevent _do_fork ^bcd=\1' # DIFF_ARG_TYPE +check_error 'p:kprobes/testevent _do_fork ^abcd=\1:u8' # DIFF_ARG_TYPE +check_error 'p:kprobes/testevent _do_fork ^abcd=\"foo"' # DIFF_ARG_TYPE +check_error '^p:kprobes/testevent _do_fork' # SAME_PROBE +fi + exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc index 7717c0a09686..ac738500d17f 100644 --- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc +++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-snapshot.tc @@ -28,7 +28,7 @@ if [ -z "$FEATURE" ]; then exit_unsupported fi -echo "Test snapshot tigger" +echo "Test snapshot trigger" echo 0 > snapshot echo 1 > events/sched/sched_process_fork/enable ( echo "forked") diff --git a/tools/testing/selftests/kexec/test_kexec_file_load.sh b/tools/testing/selftests/kexec/test_kexec_file_load.sh index fa7c24e8eefb..2ff600388c30 100755 --- a/tools/testing/selftests/kexec/test_kexec_file_load.sh +++ b/tools/testing/selftests/kexec/test_kexec_file_load.sh @@ -37,11 +37,20 @@ is_ima_sig_required() # sequentially. As a result, a policy rule may be defined, but # might not necessarily be used. This test assumes if a policy # rule is specified, that is the intent. + + # First check for appended signature (modsig), then xattr if [ $ima_read_policy -eq 1 ]; then check_ima_policy "appraise" "func=KEXEC_KERNEL_CHECK" \ - "appraise_type=imasig" + "appraise_type=imasig|modsig" ret=$? - [ $ret -eq 1 ] && log_info "IMA signature required"; + if [ $ret -eq 1 ]; then + log_info "IMA or appended(modsig) signature required" + else + check_ima_policy "appraise" "func=KEXEC_KERNEL_CHECK" \ + "appraise_type=imasig" + ret=$? + [ $ret -eq 1 ] && log_info "IMA signature required"; + fi fi return $ret } @@ -84,6 +93,22 @@ check_for_imasig() return $ret } +# Return 1 for appended signature (modsig) found and 0 for not found. +check_for_modsig() +{ + local module_sig_string="~Module signature appended~" + local sig="$(tail --bytes $((${#module_sig_string} + 1)) $KERNEL_IMAGE)" + local ret=0 + + if [ "$sig" == "$module_sig_string" ]; then + ret=1 + log_info "kexec kernel image modsig signed" + else + log_info "kexec kernel image not modsig signed" + fi + return $ret +} + kexec_file_load_test() { local succeed_msg="kexec_file_load succeeded" @@ -98,7 +123,8 @@ kexec_file_load_test() # In secureboot mode with an architecture specific # policy, make sure either an IMA or PE signature exists. if [ $secureboot -eq 1 ] && [ $arch_policy -eq 1 ] && \ - [ $ima_signed -eq 0 ] && [ $pe_signed -eq 0 ]; then + [ $ima_signed -eq 0 ] && [ $pe_signed -eq 0 ] \ + && [ $ima_modsig -eq 0 ]; then log_fail "$succeed_msg (missing sig)" fi @@ -107,7 +133,8 @@ kexec_file_load_test() log_fail "$succeed_msg (missing PE sig)" fi - if [ $ima_sig_required -eq 1 ] && [ $ima_signed -eq 0 ]; then + if [ $ima_sig_required -eq 1 ] && [ $ima_signed -eq 0 ] \ + && [ $ima_modsig -eq 0 ]; then log_fail "$succeed_msg (missing IMA sig)" fi @@ -204,5 +231,8 @@ pe_signed=$? check_for_imasig ima_signed=$? +check_for_modsig +ima_modsig=$? + # Test loading the kernel image via kexec_file_load syscall kexec_file_load_test diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index dc3346e090f5..5614222a6628 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -19,8 +19,6 @@ #include "kvm_util.h" #include "processor.h" -#define DEBUG printf - #define VCPU_ID 1 /* The memory slot index to track dirty pages */ @@ -249,14 +247,12 @@ static void vm_dirty_log_verify(unsigned long *bmap) } static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, - uint64_t extra_mem_pages, void *guest_code, - unsigned long type) + uint64_t extra_mem_pages, void *guest_code) { struct kvm_vm *vm; uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; - vm = _vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, - O_RDWR, type); + vm = _vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); kvm_vm_elf_load(vm, program_invocation_name, 0, 0); #ifdef __x86_64__ vm_create_irqchip(vm); @@ -265,67 +261,35 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, return vm; } +#define DIRTY_MEM_BITS 30 /* 1G */ +#define PAGE_SHIFT_4K 12 + static void run_test(enum vm_guest_mode mode, unsigned long iterations, unsigned long interval, uint64_t phys_offset) { - unsigned int guest_pa_bits, guest_page_shift; pthread_t vcpu_thread; struct kvm_vm *vm; - uint64_t max_gfn; unsigned long *bmap; - unsigned long type = 0; - - switch (mode) { - case VM_MODE_P52V48_4K: - guest_pa_bits = 52; - guest_page_shift = 12; - break; - case VM_MODE_P52V48_64K: - guest_pa_bits = 52; - guest_page_shift = 16; - break; - case VM_MODE_P48V48_4K: - guest_pa_bits = 48; - guest_page_shift = 12; - break; - case VM_MODE_P48V48_64K: - guest_pa_bits = 48; - guest_page_shift = 16; - break; - case VM_MODE_P40V48_4K: - guest_pa_bits = 40; - guest_page_shift = 12; - break; - case VM_MODE_P40V48_64K: - guest_pa_bits = 40; - guest_page_shift = 16; - break; - default: - TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); - } - DEBUG("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - -#ifdef __x86_64__ /* - * FIXME - * The x86_64 kvm selftests framework currently only supports a - * single PML4 which restricts the number of physical address - * bits we can change to 39. + * We reserve page table for 2 times of extra dirty mem which + * will definitely cover the original (1G+) test range. Here + * we do the calculation with 4K page size which is the + * smallest so the page number will be enough for all archs + * (e.g., 64K page size guest will need even less memory for + * page tables). */ - guest_pa_bits = 39; -#endif -#ifdef __aarch64__ - if (guest_pa_bits != 40) - type = KVM_VM_TYPE_ARM_IPA_SIZE(guest_pa_bits); -#endif - max_gfn = (1ul << (guest_pa_bits - guest_page_shift)) - 1; - guest_page_size = (1ul << guest_page_shift); + vm = create_vm(mode, VCPU_ID, + 2ul << (DIRTY_MEM_BITS - PAGE_SHIFT_4K), + guest_code); + + guest_page_size = vm_get_page_size(vm); /* * A little more than 1G of guest page sized pages. Cover the * case where the size is not aligned to 64 pages. */ - guest_num_pages = (1ul << (30 - guest_page_shift)) + 16; + guest_num_pages = (1ul << (DIRTY_MEM_BITS - + vm_get_page_shift(vm))) + 16; #ifdef __s390x__ /* Round up to multiple of 1M (segment size) */ guest_num_pages = (guest_num_pages + 0xff) & ~0xffUL; @@ -335,7 +299,8 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, !!((guest_num_pages * guest_page_size) % host_page_size); if (!phys_offset) { - guest_test_phys_mem = (max_gfn - guest_num_pages) * guest_page_size; + guest_test_phys_mem = (vm_get_max_gfn(vm) - + guest_num_pages) * guest_page_size; guest_test_phys_mem &= ~(host_page_size - 1); } else { guest_test_phys_mem = phys_offset; @@ -351,8 +316,6 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations, bmap = bitmap_alloc(host_num_pages); host_bmap_track = bitmap_alloc(host_num_pages); - vm = create_vm(mode, VCPU_ID, guest_num_pages, guest_code, type); - #ifdef USE_CLEAR_DIRTY_LOG struct kvm_enable_cap cap = {}; @@ -482,7 +445,7 @@ int main(int argc, char *argv[]) #endif #ifdef __x86_64__ - vm_guest_mode_params_init(VM_MODE_P52V48_4K, true, true); + vm_guest_mode_params_init(VM_MODE_PXXV48_4K, true, true); #endif #ifdef __aarch64__ vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true); diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 5463b7896a0a..29cccaf96baf 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -24,6 +24,12 @@ struct kvm_vm; typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ +#ifndef NDEBUG +#define DEBUG(...) printf(__VA_ARGS__); +#else +#define DEBUG(...) +#endif + /* Minimum allocated guest virtual and physical addresses */ #define KVM_UTIL_MIN_VADDR 0x2000 @@ -38,11 +44,14 @@ enum vm_guest_mode { VM_MODE_P48V48_64K, VM_MODE_P40V48_4K, VM_MODE_P40V48_64K, + VM_MODE_PXXV48_4K, /* For 48bits VA but ANY bits PA */ NUM_VM_MODES, }; -#ifdef __aarch64__ +#if defined(__aarch64__) #define VM_MODE_DEFAULT VM_MODE_P40V48_4K +#elif defined(__x86_64__) +#define VM_MODE_DEFAULT VM_MODE_PXXV48_4K #else #define VM_MODE_DEFAULT VM_MODE_P52V48_4K #endif @@ -60,8 +69,7 @@ int kvm_check_cap(long cap); int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); -struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, - int perm, unsigned long type); +struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); void kvm_vm_free(struct kvm_vm *vmp); void kvm_vm_restart(struct kvm_vm *vmp, int perm); void kvm_vm_release(struct kvm_vm *vmp); @@ -146,6 +154,10 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); bool vm_is_unrestricted_guest(struct kvm_vm *vm); +unsigned int vm_get_page_size(struct kvm_vm *vm); +unsigned int vm_get_page_shift(struct kvm_vm *vm); +unsigned int vm_get_max_gfn(struct kvm_vm *vm); + struct kvm_userspace_memory_region * kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 80d19740d2dc..0c17f2ee685e 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -325,6 +325,9 @@ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value); +uint32_t kvm_get_cpuid_max(void); +void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits); + /* * Basic CPU control in CR0 */ diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 486400a97374..86036a59a668 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -264,6 +264,9 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, int vcpuid, struct kvm_vcpu_init *ini case VM_MODE_P52V48_4K: TEST_ASSERT(false, "AArch64 does not support 4K sized pages " "with 52-bit physical address ranges"); + case VM_MODE_PXXV48_4K: + TEST_ASSERT(false, "AArch64 does not support 4K sized pages " + "with ANY-bit physical address ranges"); case VM_MODE_P52V48_64K: tcr_el1 |= 1ul << 14; /* TG0 = 64KB */ tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 6e49bb039376..80a338b5403c 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -8,6 +8,7 @@ #include "test_util.h" #include "kvm_util.h" #include "kvm_util_internal.h" +#include "processor.h" #include <assert.h> #include <sys/mman.h> @@ -84,7 +85,7 @@ int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) return ret; } -static void vm_open(struct kvm_vm *vm, int perm, unsigned long type) +static void vm_open(struct kvm_vm *vm, int perm) { vm->kvm_fd = open(KVM_DEV_PATH, perm); if (vm->kvm_fd < 0) @@ -95,18 +96,19 @@ static void vm_open(struct kvm_vm *vm, int perm, unsigned long type) exit(KSFT_SKIP); } - vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, type); + vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, vm->type); TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " "rc: %i errno: %i", vm->fd, errno); } const char * const vm_guest_mode_string[] = { - "PA-bits:52, VA-bits:48, 4K pages", - "PA-bits:52, VA-bits:48, 64K pages", - "PA-bits:48, VA-bits:48, 4K pages", - "PA-bits:48, VA-bits:48, 64K pages", - "PA-bits:40, VA-bits:48, 4K pages", - "PA-bits:40, VA-bits:48, 64K pages", + "PA-bits:52, VA-bits:48, 4K pages", + "PA-bits:52, VA-bits:48, 64K pages", + "PA-bits:48, VA-bits:48, 4K pages", + "PA-bits:48, VA-bits:48, 64K pages", + "PA-bits:40, VA-bits:48, 4K pages", + "PA-bits:40, VA-bits:48, 64K pages", + "PA-bits:ANY, VA-bits:48, 4K pages", }; _Static_assert(sizeof(vm_guest_mode_string)/sizeof(char *) == NUM_VM_MODES, "Missing new mode strings?"); @@ -130,17 +132,17 @@ _Static_assert(sizeof(vm_guest_mode_string)/sizeof(char *) == NUM_VM_MODES, * descriptor to control the created VM is created with the permissions * given by perm (e.g. O_RDWR). */ -struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, - int perm, unsigned long type) +struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) { struct kvm_vm *vm; + DEBUG("Testing guest mode: %s\n", vm_guest_mode_string(mode)); + vm = calloc(1, sizeof(*vm)); TEST_ASSERT(vm != NULL, "Insufficient Memory"); vm->mode = mode; - vm->type = type; - vm_open(vm, perm, type); + vm->type = 0; /* Setup mode specific traits. */ switch (vm->mode) { @@ -186,10 +188,32 @@ struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, vm->page_size = 0x10000; vm->page_shift = 16; break; + case VM_MODE_PXXV48_4K: +#ifdef __x86_64__ + kvm_get_cpu_address_width(&vm->pa_bits, &vm->va_bits); + TEST_ASSERT(vm->va_bits == 48, "Linear address width " + "(%d bits) not supported", vm->va_bits); + vm->pgtable_levels = 4; + vm->page_size = 0x1000; + vm->page_shift = 12; + DEBUG("Guest physical address width detected: %d\n", + vm->pa_bits); +#else + TEST_ASSERT(false, "VM_MODE_PXXV48_4K not supported on " + "non-x86 platforms"); +#endif + break; default: TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); } +#ifdef __aarch64__ + if (vm->pa_bits != 40) + vm->type = KVM_VM_TYPE_ARM_IPA_SIZE(vm->pa_bits); +#endif + + vm_open(vm, perm); + /* Limit to VA-bit canonical virtual addresses. */ vm->vpages_valid = sparsebit_alloc(); sparsebit_set_num(vm->vpages_valid, @@ -212,7 +236,7 @@ struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) { - return _vm_create(mode, phy_pages, perm, 0); + return _vm_create(mode, phy_pages, perm); } /* @@ -232,7 +256,7 @@ void kvm_vm_restart(struct kvm_vm *vmp, int perm) { struct userspace_mem_region *region; - vm_open(vmp, perm, vmp->type); + vm_open(vmp, perm); if (vmp->has_irqchip) vm_create_irqchip(vmp); @@ -1628,3 +1652,18 @@ bool vm_is_unrestricted_guest(struct kvm_vm *vm) return val == 'Y'; } + +unsigned int vm_get_page_size(struct kvm_vm *vm) +{ + return vm->page_size; +} + +unsigned int vm_get_page_shift(struct kvm_vm *vm) +{ + return vm->page_shift; +} + +unsigned int vm_get_max_gfn(struct kvm_vm *vm) +{ + return vm->max_gfn; +} diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 0a5e487dbc50..c53dbc6bc568 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -228,7 +228,7 @@ void sregs_dump(FILE *stream, struct kvm_sregs *sregs, void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) { - TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " + TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); /* If needed, create page map l4 table. */ @@ -261,7 +261,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, uint16_t index[4]; struct pageMapL4Entry *pml4e; - TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " + TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); TEST_ASSERT((vaddr % vm->page_size) == 0, @@ -547,7 +547,7 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) struct pageDirectoryEntry *pde; struct pageTableEntry *pte; - TEST_ASSERT(vm->mode == VM_MODE_P52V48_4K, "Attempt to use " + TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); index[0] = (gva >> 12) & 0x1ffu; @@ -621,7 +621,7 @@ static void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_m kvm_setup_gdt(vm, &sregs.gdt, gdt_memslot, pgd_memslot); switch (vm->mode) { - case VM_MODE_P52V48_4K: + case VM_MODE_PXXV48_4K: sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR; sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); @@ -1157,3 +1157,25 @@ bool is_intel_cpu(void) chunk = (const uint32_t *)("GenuineIntel"); return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]); } + +uint32_t kvm_get_cpuid_max(void) +{ + return kvm_get_supported_cpuid_entry(0x80000000)->eax; +} + +void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) +{ + struct kvm_cpuid_entry2 *entry; + bool pae; + + /* SDM 4.1.4 */ + if (kvm_get_cpuid_max() < 0x80000008) { + pae = kvm_get_supported_cpuid_entry(1)->edx & (1 << 6); + *pa_bits = pae ? 36 : 32; + *va_bits = 32; + } else { + entry = kvm_get_supported_cpuid_entry(0x80000008); + *pa_bits = entry->eax & 0xff; + *va_bits = (entry->eax >> 8) & 0xff; + } +} diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c index 4bfc9a90b1de..da4d89ad5419 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c @@ -32,7 +32,7 @@ void ucall(uint64_t cmd, int nargs, ...) va_end(va); asm volatile("in %[port], %%al" - : : [port] "d" (UCALL_PIO_PORT), "D" (&uc) : "rax"); + : : [port] "d" (UCALL_PIO_PORT), "D" (&uc) : "rax", "memory"); } uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index ee59831fbc98..443a2b54645b 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -26,6 +26,25 @@ static void guest_code(void) { } +static int smt_possible(void) +{ + char buf[16]; + FILE *f; + bool res = 1; + + f = fopen("/sys/devices/system/cpu/smt/control", "r"); + if (f) { + if (fread(buf, sizeof(*buf), sizeof(buf), f) > 0) { + if (!strncmp(buf, "forceoff", 8) || + !strncmp(buf, "notsupported", 12)) + res = 0; + } + fclose(f); + } + + return res; +} + static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries, int evmcs_enabled) { @@ -59,6 +78,14 @@ static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries, TEST_ASSERT(!entry->padding[0] && !entry->padding[1] && !entry->padding[2], "padding should be zero"); + if (entry->function == 0x40000004) { + int nononarchcs = !!(entry->eax & (1UL << 18)); + + TEST_ASSERT(nononarchcs == !smt_possible(), + "NoNonArchitecturalCoreSharing bit" + " doesn't reflect SMT setting"); + } + /* * If needed for debug: * fprintf(stdout, diff --git a/tools/testing/selftests/livepatch/config b/tools/testing/selftests/livepatch/config index 0dd7700464a8..ad23100cb27c 100644 --- a/tools/testing/selftests/livepatch/config +++ b/tools/testing/selftests/livepatch/config @@ -1 +1,3 @@ +CONFIG_LIVEPATCH=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_TEST_LIVEPATCH=m diff --git a/tools/testing/selftests/membarrier/.gitignore b/tools/testing/selftests/membarrier/.gitignore index 020c44f49a9e..f2f7ec0a99b4 100644 --- a/tools/testing/selftests/membarrier/.gitignore +++ b/tools/testing/selftests/membarrier/.gitignore @@ -1 +1,2 @@ -membarrier_test +membarrier_test_multi_thread +membarrier_test_single_thread diff --git a/tools/testing/selftests/membarrier/Makefile b/tools/testing/selftests/membarrier/Makefile index 97e3bdf3d1e9..34d1c81a2324 100644 --- a/tools/testing/selftests/membarrier/Makefile +++ b/tools/testing/selftests/membarrier/Makefile @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only CFLAGS += -g -I../../../../usr/include/ +LDLIBS += -lpthread -TEST_GEN_PROGS := membarrier_test +TEST_GEN_PROGS := membarrier_test_single_thread \ + membarrier_test_multi_thread include ../lib.mk - diff --git a/tools/testing/selftests/membarrier/membarrier_test.c b/tools/testing/selftests/membarrier/membarrier_test_impl.h index 70b4ddbf126b..186be69f0a59 100644 --- a/tools/testing/selftests/membarrier/membarrier_test.c +++ b/tools/testing/selftests/membarrier/membarrier_test_impl.h @@ -1,10 +1,11 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ #define _GNU_SOURCE #include <linux/membarrier.h> #include <syscall.h> #include <stdio.h> #include <errno.h> #include <string.h> +#include <pthread.h> #include "../kselftest.h" @@ -223,7 +224,7 @@ static int test_membarrier_global_expedited_success(void) return 0; } -static int test_membarrier(void) +static int test_membarrier_fail(void) { int status; @@ -233,10 +234,27 @@ static int test_membarrier(void) status = test_membarrier_flags_fail(); if (status) return status; - status = test_membarrier_global_success(); + status = test_membarrier_private_expedited_fail(); if (status) return status; - status = test_membarrier_private_expedited_fail(); + status = sys_membarrier(MEMBARRIER_CMD_QUERY, 0); + if (status < 0) { + ksft_test_result_fail("sys_membarrier() failed\n"); + return status; + } + if (status & MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE) { + status = test_membarrier_private_expedited_sync_core_fail(); + if (status) + return status; + } + return 0; +} + +static int test_membarrier_success(void) +{ + int status; + + status = test_membarrier_global_success(); if (status) return status; status = test_membarrier_register_private_expedited_success(); @@ -251,9 +269,6 @@ static int test_membarrier(void) return status; } if (status & MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE) { - status = test_membarrier_private_expedited_sync_core_fail(); - if (status) - return status; status = test_membarrier_register_private_expedited_sync_core_success(); if (status) return status; @@ -300,14 +315,3 @@ static int test_membarrier_query(void) ksft_test_result_pass("sys_membarrier available\n"); return 0; } - -int main(int argc, char **argv) -{ - ksft_print_header(); - ksft_set_plan(13); - - test_membarrier_query(); - test_membarrier(); - - return ksft_exit_pass(); -} diff --git a/tools/testing/selftests/membarrier/membarrier_test_multi_thread.c b/tools/testing/selftests/membarrier/membarrier_test_multi_thread.c new file mode 100644 index 000000000000..ac5613e5b0eb --- /dev/null +++ b/tools/testing/selftests/membarrier/membarrier_test_multi_thread.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <linux/membarrier.h> +#include <syscall.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> + +#include "membarrier_test_impl.h" + +static int thread_ready, thread_quit; +static pthread_mutex_t test_membarrier_thread_mutex = + PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t test_membarrier_thread_cond = + PTHREAD_COND_INITIALIZER; + +void *test_membarrier_thread(void *arg) +{ + pthread_mutex_lock(&test_membarrier_thread_mutex); + thread_ready = 1; + pthread_cond_broadcast(&test_membarrier_thread_cond); + pthread_mutex_unlock(&test_membarrier_thread_mutex); + + pthread_mutex_lock(&test_membarrier_thread_mutex); + while (!thread_quit) + pthread_cond_wait(&test_membarrier_thread_cond, + &test_membarrier_thread_mutex); + pthread_mutex_unlock(&test_membarrier_thread_mutex); + + return NULL; +} + +static int test_mt_membarrier(void) +{ + int i; + pthread_t test_thread; + + pthread_create(&test_thread, NULL, + test_membarrier_thread, NULL); + + pthread_mutex_lock(&test_membarrier_thread_mutex); + while (!thread_ready) + pthread_cond_wait(&test_membarrier_thread_cond, + &test_membarrier_thread_mutex); + pthread_mutex_unlock(&test_membarrier_thread_mutex); + + test_membarrier_fail(); + + test_membarrier_success(); + + pthread_mutex_lock(&test_membarrier_thread_mutex); + thread_quit = 1; + pthread_cond_broadcast(&test_membarrier_thread_cond); + pthread_mutex_unlock(&test_membarrier_thread_mutex); + + pthread_join(test_thread, NULL); + + return 0; +} + +int main(int argc, char **argv) +{ + ksft_print_header(); + ksft_set_plan(13); + + test_membarrier_query(); + + /* Multi-threaded */ + test_mt_membarrier(); + + return ksft_exit_pass(); +} diff --git a/tools/testing/selftests/membarrier/membarrier_test_single_thread.c b/tools/testing/selftests/membarrier/membarrier_test_single_thread.c new file mode 100644 index 000000000000..c1c963902854 --- /dev/null +++ b/tools/testing/selftests/membarrier/membarrier_test_single_thread.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <linux/membarrier.h> +#include <syscall.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> + +#include "membarrier_test_impl.h" + +int main(int argc, char **argv) +{ + ksft_print_header(); + ksft_set_plan(13); + + test_membarrier_query(); + + test_membarrier_fail(); + + test_membarrier_success(); + + return ksft_exit_pass(); +} diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index b3ad909aefbc..644770c3b754 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -26,6 +26,7 @@ SUB_DIRS = alignment \ switch_endian \ syscalls \ tm \ + eeh \ vphn \ math \ ptrace \ diff --git a/tools/testing/selftests/powerpc/copyloops/.gitignore b/tools/testing/selftests/powerpc/copyloops/.gitignore index ce12cd0e2967..12ef5b031974 100644 --- a/tools/testing/selftests/powerpc/copyloops/.gitignore +++ b/tools/testing/selftests/powerpc/copyloops/.gitignore @@ -1,13 +1,14 @@ copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 -copyuser_power7_t0 -copyuser_power7_t1 +copyuser_p7_t0 +copyuser_p7_t1 memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 -memcpy_power7_t0 -memcpy_power7_t1 +memcpy_p7_t0 +memcpy_p7_t1 copyuser_64_exc_t0 copyuser_64_exc_t1 copyuser_64_exc_t2 +memcpy_mcsafe_64 diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index 44574f3818b3..0917983a1c78 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -12,7 +12,7 @@ ASFLAGS = $(CFLAGS) -Wa,-mpower4 TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \ copyuser_p7_t0 copyuser_p7_t1 \ memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \ - memcpy_p7_t0 memcpy_p7_t1 \ + memcpy_p7_t0 memcpy_p7_t1 memcpy_mcsafe_64 \ copyuser_64_exc_t0 copyuser_64_exc_t1 copyuser_64_exc_t2 EXTRA_SOURCES := validate.c ../harness.c stubs.S @@ -45,6 +45,11 @@ $(OUTPUT)/memcpy_p7_t%: memcpy_power7.S $(EXTRA_SOURCES) -D SELFTEST_CASE=$(subst memcpy_p7_t,,$(notdir $@)) \ -o $@ $^ +$(OUTPUT)/memcpy_mcsafe_64: memcpy_mcsafe_64.S $(EXTRA_SOURCES) + $(CC) $(CPPFLAGS) $(CFLAGS) \ + -D COPY_LOOP=test_memcpy_mcsafe \ + -o $@ $^ + $(OUTPUT)/copyuser_64_exc_t%: copyuser_64.S exc_validate.c ../harness.c \ copy_tofrom_user_reference.S stubs.S $(CC) $(CPPFLAGS) $(CFLAGS) \ diff --git a/tools/testing/selftests/powerpc/copyloops/asm/export.h b/tools/testing/selftests/powerpc/copyloops/asm/export.h index 05c1663c89b0..e6b80d5fbd14 100644 --- a/tools/testing/selftests/powerpc/copyloops/asm/export.h +++ b/tools/testing/selftests/powerpc/copyloops/asm/export.h @@ -1,3 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ #define EXPORT_SYMBOL(x) +#define EXPORT_SYMBOL_GPL(x) #define EXPORT_SYMBOL_KASAN(x) diff --git a/tools/testing/selftests/powerpc/copyloops/memcpy_mcsafe_64.S b/tools/testing/selftests/powerpc/copyloops/memcpy_mcsafe_64.S new file mode 120000 index 000000000000..f0feef3062f6 --- /dev/null +++ b/tools/testing/selftests/powerpc/copyloops/memcpy_mcsafe_64.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcpy_mcsafe_64.S
\ No newline at end of file diff --git a/tools/testing/selftests/powerpc/eeh/Makefile b/tools/testing/selftests/powerpc/eeh/Makefile new file mode 100644 index 000000000000..b397babd569b --- /dev/null +++ b/tools/testing/selftests/powerpc/eeh/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +noarg: + $(MAKE) -C ../ + +TEST_PROGS := eeh-basic.sh +TEST_FILES := eeh-functions.sh + +top_srcdir = ../../../../.. +include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/eeh/eeh-basic.sh b/tools/testing/selftests/powerpc/eeh/eeh-basic.sh new file mode 100755 index 000000000000..f988d2f42e8f --- /dev/null +++ b/tools/testing/selftests/powerpc/eeh/eeh-basic.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +. ./eeh-functions.sh + +if ! eeh_supported ; then + echo "EEH not supported on this system, skipping" + exit 0; +fi + +if [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_check" ] && \ + [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_break" ] ; then + echo "debugfs EEH testing files are missing. Is debugfs mounted?" + exit 1; +fi + +pre_lspci=`mktemp` +lspci > $pre_lspci + +# Bump the max freeze count to something absurd so we don't +# trip over it while breaking things. +echo 5000 > /sys/kernel/debug/powerpc/eeh_max_freezes + +# record the devices that we break in here. Assuming everything +# goes to plan we should get them back once the recover process +# is finished. +devices="" + +# Build up a list of candidate devices. +for dev in `ls -1 /sys/bus/pci/devices/ | grep '\.0$'` ; do + # skip bridges since we can't recover them (yet...) + if [ -e "/sys/bus/pci/devices/$dev/pci_bus" ] ; then + echo "$dev, Skipped: bridge" + continue; + fi + + # Skip VFs for now since we don't have a reliable way + # to break them. + if [ -e "/sys/bus/pci/devices/$dev/physfn" ] ; then + echo "$dev, Skipped: virtfn" + continue; + fi + + # Don't inject errosr into an already-frozen PE. This happens with + # PEs that contain multiple PCI devices (e.g. multi-function cards) + # and injecting new errors during the recovery process will probably + # result in the recovery failing and the device being marked as + # failed. + if ! pe_ok $dev ; then + echo "$dev, Skipped: Bad initial PE state" + continue; + fi + + echo "$dev, Added" + + # Add to this list of device to check + devices="$devices $dev" +done + +dev_count="$(echo $devices | wc -w)" +echo "Found ${dev_count} breakable devices..." + +failed=0 +for dev in $devices ; do + echo "Breaking $dev..." + + if ! pe_ok $dev ; then + echo "Skipping $dev, Initial PE state is not ok" + failed="$((failed + 1))" + continue; + fi + + if ! eeh_one_dev $dev ; then + failed="$((failed + 1))" + fi +done + +echo "$failed devices failed to recover ($dev_count tested)" +lspci | diff -u $pre_lspci - +rm -f $pre_lspci + +exit $failed diff --git a/tools/testing/selftests/powerpc/eeh/eeh-functions.sh b/tools/testing/selftests/powerpc/eeh/eeh-functions.sh new file mode 100755 index 000000000000..26112ab5cdf4 --- /dev/null +++ b/tools/testing/selftests/powerpc/eeh/eeh-functions.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +pe_ok() { + local dev="$1" + local path="/sys/bus/pci/devices/$dev/eeh_pe_state" + + if ! [ -e "$path" ] ; then + return 1; + fi + + local fw_state="$(cut -d' ' -f1 < $path)" + local sw_state="$(cut -d' ' -f2 < $path)" + + # If EEH_PE_ISOLATED or EEH_PE_RECOVERING are set then the PE is in an + # error state or being recovered. Either way, not ok. + if [ "$((sw_state & 0x3))" -ne 0 ] ; then + return 1 + fi + + # A functioning PE should have the EEH_STATE_MMIO_ACTIVE and + # EEH_STATE_DMA_ACTIVE flags set. For some goddamn stupid reason + # the platform backends set these when the PE is in reset. The + # RECOVERING check above should stop any false positives though. + if [ "$((fw_state & 0x18))" -ne "$((0x18))" ] ; then + return 1 + fi + + return 0; +} + +eeh_supported() { + test -e /proc/powerpc/eeh && \ + grep -q 'EEH Subsystem is enabled' /proc/powerpc/eeh +} + +eeh_one_dev() { + local dev="$1" + + # Using this function from the command line is sometimes useful for + # testing so check that the argument is a well-formed sysfs device + # name. + if ! test -e /sys/bus/pci/devices/$dev/ ; then + echo "Error: '$dev' must be a sysfs device name (DDDD:BB:DD.F)" + return 1; + fi + + # Break it + echo $dev >/sys/kernel/debug/powerpc/eeh_dev_break + + # Force an EEH device check. If the kernel has already + # noticed the EEH (due to a driver poll or whatever), this + # is a no-op. + echo $dev >/sys/kernel/debug/powerpc/eeh_dev_check + + # Enforce a 30s timeout for recovery. Even the IPR, which is infamously + # slow to reset, should recover within 30s. + max_wait=30 + + for i in `seq 0 ${max_wait}` ; do + if pe_ok $dev ; then + break; + fi + echo "$dev, waited $i/${max_wait}" + sleep 1 + done + + if ! pe_ok $dev ; then + echo "$dev, Failed to recover!" + return 1; + fi + + echo "$dev, Recovered after $i seconds" + return 0; +} + diff --git a/tools/testing/selftests/powerpc/mm/Makefile b/tools/testing/selftests/powerpc/mm/Makefile index f1fbc15800c4..ed1565809d2b 100644 --- a/tools/testing/selftests/powerpc/mm/Makefile +++ b/tools/testing/selftests/powerpc/mm/Makefile @@ -4,6 +4,7 @@ noarg: TEST_GEN_PROGS := hugetlb_vs_thp_test subpage_prot prot_sao segv_errors wild_bctr \ large_vm_fork_separation +TEST_GEN_PROGS_EXTENDED := tlbie_test TEST_GEN_FILES := tempfile top_srcdir = ../../../../.. @@ -19,3 +20,4 @@ $(OUTPUT)/large_vm_fork_separation: CFLAGS += -m64 $(OUTPUT)/tempfile: dd if=/dev/zero of=$@ bs=64k count=1 +$(OUTPUT)/tlbie_test: LDLIBS += -lpthread diff --git a/tools/testing/selftests/powerpc/mm/tlbie_test.c b/tools/testing/selftests/powerpc/mm/tlbie_test.c new file mode 100644 index 000000000000..9868a5ddd847 --- /dev/null +++ b/tools/testing/selftests/powerpc/mm/tlbie_test.c @@ -0,0 +1,734 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019, Nick Piggin, Gautham R. Shenoy, Aneesh Kumar K.V, IBM Corp. + */ + +/* + * + * Test tlbie/mtpidr race. We have 4 threads doing flush/load/compare/store + * sequence in a loop. The same threads also rung a context switch task + * that does sched_yield() in loop. + * + * The snapshot thread mark the mmap area PROT_READ in between, make a copy + * and copy it back to the original area. This helps us to detect if any + * store continued to happen after we marked the memory PROT_READ. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <linux/futex.h> +#include <unistd.h> +#include <asm/unistd.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sched.h> +#include <time.h> +#include <stdarg.h> +#include <sched.h> +#include <pthread.h> +#include <signal.h> +#include <sys/prctl.h> + +static inline void dcbf(volatile unsigned int *addr) +{ + __asm__ __volatile__ ("dcbf %y0; sync" : : "Z"(*(unsigned char *)addr) : "memory"); +} + +static void err_msg(char *msg) +{ + + time_t now; + time(&now); + printf("=================================\n"); + printf(" Error: %s\n", msg); + printf(" %s", ctime(&now)); + printf("=================================\n"); + exit(1); +} + +static char *map1; +static char *map2; +static pid_t rim_process_pid; + +/* + * A "rim-sequence" is defined to be the sequence of the following + * operations performed on a memory word: + * 1) FLUSH the contents of that word. + * 2) LOAD the contents of that word. + * 3) COMPARE the contents of that word with the content that was + * previously stored at that word + * 4) STORE new content into that word. + * + * The threads in this test that perform the rim-sequence are termed + * as rim_threads. + */ + +/* + * A "corruption" is defined to be the failed COMPARE operation in a + * rim-sequence. + * + * A rim_thread that detects a corruption informs about it to all the + * other rim_threads, and the mem_snapshot thread. + */ +static volatile unsigned int corruption_found; + +/* + * This defines the maximum number of rim_threads in this test. + * + * The THREAD_ID_BITS denote the number of bits required + * to represent the thread_ids [0..MAX_THREADS - 1]. + * We are being a bit paranoid here and set it to 8 bits, + * though 6 bits suffice. + * + */ +#define MAX_THREADS 64 +#define THREAD_ID_BITS 8 +#define THREAD_ID_MASK ((1 << THREAD_ID_BITS) - 1) +static unsigned int rim_thread_ids[MAX_THREADS]; +static pthread_t rim_threads[MAX_THREADS]; + + +/* + * Each rim_thread works on an exclusive "chunk" of size + * RIM_CHUNK_SIZE. + * + * The ith rim_thread works on the ith chunk. + * + * The ith chunk begins at + * map1 + (i * RIM_CHUNK_SIZE) + */ +#define RIM_CHUNK_SIZE 1024 +#define BITS_PER_BYTE 8 +#define WORD_SIZE (sizeof(unsigned int)) +#define WORD_BITS (WORD_SIZE * BITS_PER_BYTE) +#define WORDS_PER_CHUNK (RIM_CHUNK_SIZE/WORD_SIZE) + +static inline char *compute_chunk_start_addr(unsigned int thread_id) +{ + char *chunk_start; + + chunk_start = (char *)((unsigned long)map1 + + (thread_id * RIM_CHUNK_SIZE)); + + return chunk_start; +} + +/* + * The "word-offset" of a word-aligned address inside a chunk, is + * defined to be the number of words that precede the address in that + * chunk. + * + * WORD_OFFSET_BITS denote the number of bits required to represent + * the word-offsets of all the word-aligned addresses of a chunk. + */ +#define WORD_OFFSET_BITS (__builtin_ctz(WORDS_PER_CHUNK)) +#define WORD_OFFSET_MASK ((1 << WORD_OFFSET_BITS) - 1) + +static inline unsigned int compute_word_offset(char *start, unsigned int *addr) +{ + unsigned int delta_bytes, ret; + delta_bytes = (unsigned long)addr - (unsigned long)start; + + ret = delta_bytes/WORD_SIZE; + + return ret; +} + +/* + * A "sweep" is defined to be the sequential execution of the + * rim-sequence by a rim_thread on its chunk one word at a time, + * starting from the first word of its chunk and ending with the last + * word of its chunk. + * + * Each sweep of a rim_thread is uniquely identified by a sweep_id. + * SWEEP_ID_BITS denote the number of bits required to represent + * the sweep_ids of rim_threads. + * + * As to why SWEEP_ID_BITS are computed as a function of THREAD_ID_BITS, + * WORD_OFFSET_BITS, and WORD_BITS, see the "store-pattern" below. + */ +#define SWEEP_ID_BITS (WORD_BITS - (THREAD_ID_BITS + WORD_OFFSET_BITS)) +#define SWEEP_ID_MASK ((1 << SWEEP_ID_BITS) - 1) + +/* + * A "store-pattern" is the word-pattern that is stored into a word + * location in the 4)STORE step of the rim-sequence. + * + * In the store-pattern, we shall encode: + * + * - The thread-id of the rim_thread performing the store + * (The most significant THREAD_ID_BITS) + * + * - The word-offset of the address into which the store is being + * performed (The next WORD_OFFSET_BITS) + * + * - The sweep_id of the current sweep in which the store is + * being performed. (The lower SWEEP_ID_BITS) + * + * Store Pattern: 32 bits + * |------------------|--------------------|---------------------------------| + * | Thread id | Word offset | sweep_id | + * |------------------|--------------------|---------------------------------| + * THREAD_ID_BITS WORD_OFFSET_BITS SWEEP_ID_BITS + * + * In the store pattern, the (Thread-id + Word-offset) uniquely identify the + * address to which the store is being performed i.e, + * address == map1 + + * (Thread-id * RIM_CHUNK_SIZE) + (Word-offset * WORD_SIZE) + * + * And the sweep_id in the store pattern identifies the time when the + * store was performed by the rim_thread. + * + * We shall use this property in the 3)COMPARE step of the + * rim-sequence. + */ +#define SWEEP_ID_SHIFT 0 +#define WORD_OFFSET_SHIFT (SWEEP_ID_BITS) +#define THREAD_ID_SHIFT (WORD_OFFSET_BITS + SWEEP_ID_BITS) + +/* + * Compute the store pattern for a given thread with id @tid, at + * location @addr in the sweep identified by @sweep_id + */ +static inline unsigned int compute_store_pattern(unsigned int tid, + unsigned int *addr, + unsigned int sweep_id) +{ + unsigned int ret = 0; + char *start = compute_chunk_start_addr(tid); + unsigned int word_offset = compute_word_offset(start, addr); + + ret += (tid & THREAD_ID_MASK) << THREAD_ID_SHIFT; + ret += (word_offset & WORD_OFFSET_MASK) << WORD_OFFSET_SHIFT; + ret += (sweep_id & SWEEP_ID_MASK) << SWEEP_ID_SHIFT; + return ret; +} + +/* Extract the thread-id from the given store-pattern */ +static inline unsigned int extract_tid(unsigned int pattern) +{ + unsigned int ret; + + ret = (pattern >> THREAD_ID_SHIFT) & THREAD_ID_MASK; + return ret; +} + +/* Extract the word-offset from the given store-pattern */ +static inline unsigned int extract_word_offset(unsigned int pattern) +{ + unsigned int ret; + + ret = (pattern >> WORD_OFFSET_SHIFT) & WORD_OFFSET_MASK; + + return ret; +} + +/* Extract the sweep-id from the given store-pattern */ +static inline unsigned int extract_sweep_id(unsigned int pattern) + +{ + unsigned int ret; + + ret = (pattern >> SWEEP_ID_SHIFT) & SWEEP_ID_MASK; + + return ret; +} + +/************************************************************ + * * + * Logging the output of the verification * + * * + ************************************************************/ +#define LOGDIR_NAME_SIZE 100 +static char logdir[LOGDIR_NAME_SIZE]; + +static FILE *fp[MAX_THREADS]; +static const char logfilename[] ="Thread-%02d-Chunk"; + +static inline void start_verification_log(unsigned int tid, + unsigned int *addr, + unsigned int cur_sweep_id, + unsigned int prev_sweep_id) +{ + FILE *f; + char logfile[30]; + char path[LOGDIR_NAME_SIZE + 30]; + char separator[2] = "/"; + char *chunk_start = compute_chunk_start_addr(tid); + unsigned int size = RIM_CHUNK_SIZE; + + sprintf(logfile, logfilename, tid); + strcpy(path, logdir); + strcat(path, separator); + strcat(path, logfile); + f = fopen(path, "w"); + + if (!f) { + err_msg("Unable to create logfile\n"); + } + + fp[tid] = f; + + fprintf(f, "----------------------------------------------------------\n"); + fprintf(f, "PID = %d\n", rim_process_pid); + fprintf(f, "Thread id = %02d\n", tid); + fprintf(f, "Chunk Start Addr = 0x%016lx\n", (unsigned long)chunk_start); + fprintf(f, "Chunk Size = %d\n", size); + fprintf(f, "Next Store Addr = 0x%016lx\n", (unsigned long)addr); + fprintf(f, "Current sweep-id = 0x%08x\n", cur_sweep_id); + fprintf(f, "Previous sweep-id = 0x%08x\n", prev_sweep_id); + fprintf(f, "----------------------------------------------------------\n"); +} + +static inline void log_anamoly(unsigned int tid, unsigned int *addr, + unsigned int expected, unsigned int observed) +{ + FILE *f = fp[tid]; + + fprintf(f, "Thread %02d: Addr 0x%lx: Expected 0x%x, Observed 0x%x\n", + tid, (unsigned long)addr, expected, observed); + fprintf(f, "Thread %02d: Expected Thread id = %02d\n", tid, extract_tid(expected)); + fprintf(f, "Thread %02d: Observed Thread id = %02d\n", tid, extract_tid(observed)); + fprintf(f, "Thread %02d: Expected Word offset = %03d\n", tid, extract_word_offset(expected)); + fprintf(f, "Thread %02d: Observed Word offset = %03d\n", tid, extract_word_offset(observed)); + fprintf(f, "Thread %02d: Expected sweep-id = 0x%x\n", tid, extract_sweep_id(expected)); + fprintf(f, "Thread %02d: Observed sweep-id = 0x%x\n", tid, extract_sweep_id(observed)); + fprintf(f, "----------------------------------------------------------\n"); +} + +static inline void end_verification_log(unsigned int tid, unsigned nr_anamolies) +{ + FILE *f = fp[tid]; + char logfile[30]; + char path[LOGDIR_NAME_SIZE + 30]; + char separator[] = "/"; + + fclose(f); + + if (nr_anamolies == 0) { + remove(path); + return; + } + + sprintf(logfile, logfilename, tid); + strcpy(path, logdir); + strcat(path, separator); + strcat(path, logfile); + + printf("Thread %02d chunk has %d corrupted words. For details check %s\n", + tid, nr_anamolies, path); +} + +/* + * When a COMPARE step of a rim-sequence fails, the rim_thread informs + * everyone else via the shared_memory pointed to by + * corruption_found variable. On seeing this, every thread verifies the + * content of its chunk as follows. + * + * Suppose a thread identified with @tid was about to store (but not + * yet stored) to @next_store_addr in its current sweep identified + * @cur_sweep_id. Let @prev_sweep_id indicate the previous sweep_id. + * + * This implies that for all the addresses @addr < @next_store_addr, + * Thread @tid has already performed a store as part of its current + * sweep. Hence we expect the content of such @addr to be: + * |-------------------------------------------------| + * | tid | word_offset(addr) | cur_sweep_id | + * |-------------------------------------------------| + * + * Since Thread @tid is yet to perform stores on address + * @next_store_addr and above, we expect the content of such an + * address @addr to be: + * |-------------------------------------------------| + * | tid | word_offset(addr) | prev_sweep_id | + * |-------------------------------------------------| + * + * The verifier function @verify_chunk does this verification and logs + * any anamolies that it finds. + */ +static void verify_chunk(unsigned int tid, unsigned int *next_store_addr, + unsigned int cur_sweep_id, + unsigned int prev_sweep_id) +{ + unsigned int *iter_ptr; + unsigned int size = RIM_CHUNK_SIZE; + unsigned int expected; + unsigned int observed; + char *chunk_start = compute_chunk_start_addr(tid); + + int nr_anamolies = 0; + + start_verification_log(tid, next_store_addr, + cur_sweep_id, prev_sweep_id); + + for (iter_ptr = (unsigned int *)chunk_start; + (unsigned long)iter_ptr < (unsigned long)chunk_start + size; + iter_ptr++) { + unsigned int expected_sweep_id; + + if (iter_ptr < next_store_addr) { + expected_sweep_id = cur_sweep_id; + } else { + expected_sweep_id = prev_sweep_id; + } + + expected = compute_store_pattern(tid, iter_ptr, expected_sweep_id); + + dcbf((volatile unsigned int*)iter_ptr); //Flush before reading + observed = *iter_ptr; + + if (observed != expected) { + nr_anamolies++; + log_anamoly(tid, iter_ptr, expected, observed); + } + } + + end_verification_log(tid, nr_anamolies); +} + +static void set_pthread_cpu(pthread_t th, int cpu) +{ + cpu_set_t run_cpu_mask; + struct sched_param param; + + CPU_ZERO(&run_cpu_mask); + CPU_SET(cpu, &run_cpu_mask); + pthread_setaffinity_np(th, sizeof(cpu_set_t), &run_cpu_mask); + + param.sched_priority = 1; + if (0 && sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) { + /* haven't reproduced with this setting, it kills random preemption which may be a factor */ + fprintf(stderr, "could not set SCHED_FIFO, run as root?\n"); + } +} + +static void set_mycpu(int cpu) +{ + cpu_set_t run_cpu_mask; + struct sched_param param; + + CPU_ZERO(&run_cpu_mask); + CPU_SET(cpu, &run_cpu_mask); + sched_setaffinity(0, sizeof(cpu_set_t), &run_cpu_mask); + + param.sched_priority = 1; + if (0 && sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) { + fprintf(stderr, "could not set SCHED_FIFO, run as root?\n"); + } +} + +static volatile int segv_wait; + +static void segv_handler(int signo, siginfo_t *info, void *extra) +{ + while (segv_wait) { + sched_yield(); + } + +} + +static void set_segv_handler(void) +{ + struct sigaction sa; + + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = segv_handler; + + if (sigaction(SIGSEGV, &sa, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } +} + +int timeout = 0; +/* + * This function is executed by every rim_thread. + * + * This function performs sweeps over the exclusive chunks of the + * rim_threads executing the rim-sequence one word at a time. + */ +static void *rim_fn(void *arg) +{ + unsigned int tid = *((unsigned int *)arg); + + int size = RIM_CHUNK_SIZE; + char *chunk_start = compute_chunk_start_addr(tid); + + unsigned int prev_sweep_id; + unsigned int cur_sweep_id = 0; + + /* word access */ + unsigned int pattern = cur_sweep_id; + unsigned int *pattern_ptr = &pattern; + unsigned int *w_ptr, read_data; + + set_segv_handler(); + + /* + * Let us initialize the chunk: + * + * Each word-aligned address addr in the chunk, + * is initialized to : + * |-------------------------------------------------| + * | tid | word_offset(addr) | 0 | + * |-------------------------------------------------| + */ + for (w_ptr = (unsigned int *)chunk_start; + (unsigned long)w_ptr < (unsigned long)(chunk_start) + size; + w_ptr++) { + + *pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id); + *w_ptr = *pattern_ptr; + } + + while (!corruption_found && !timeout) { + prev_sweep_id = cur_sweep_id; + cur_sweep_id = cur_sweep_id + 1; + + for (w_ptr = (unsigned int *)chunk_start; + (unsigned long)w_ptr < (unsigned long)(chunk_start) + size; + w_ptr++) { + unsigned int old_pattern; + + /* + * Compute the pattern that we would have + * stored at this location in the previous + * sweep. + */ + old_pattern = compute_store_pattern(tid, w_ptr, prev_sweep_id); + + /* + * FLUSH:Ensure that we flush the contents of + * the cache before loading + */ + dcbf((volatile unsigned int*)w_ptr); //Flush + + /* LOAD: Read the value */ + read_data = *w_ptr; //Load + + /* + * COMPARE: Is it the same as what we had stored + * in the previous sweep ? It better be! + */ + if (read_data != old_pattern) { + /* No it isn't! Tell everyone */ + corruption_found = 1; + } + + /* + * Before performing a store, let us check if + * any rim_thread has found a corruption. + */ + if (corruption_found || timeout) { + /* + * Yes. Someone (including us!) has found + * a corruption :( + * + * Let us verify that our chunk is + * correct. + */ + /* But first, let us allow the dust to settle down! */ + verify_chunk(tid, w_ptr, cur_sweep_id, prev_sweep_id); + + return 0; + } + + /* + * Compute the new pattern that we are going + * to write to this location + */ + *pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id); + + /* + * STORE: Now let us write this pattern into + * the location + */ + *w_ptr = *pattern_ptr; + } + } + + return NULL; +} + + +static unsigned long start_cpu = 0; +static unsigned long nrthreads = 4; + +static pthread_t mem_snapshot_thread; + +static void *mem_snapshot_fn(void *arg) +{ + int page_size = getpagesize(); + size_t size = page_size; + void *tmp = malloc(size); + + while (!corruption_found && !timeout) { + /* Stop memory migration once corruption is found */ + segv_wait = 1; + + mprotect(map1, size, PROT_READ); + + /* + * Load from the working alias (map1). Loading from map2 + * also fails. + */ + memcpy(tmp, map1, size); + + /* + * Stores must go via map2 which has write permissions, but + * the corrupted data tends to be seen in the snapshot buffer, + * so corruption does not appear to be introduced at the + * copy-back via map2 alias here. + */ + memcpy(map2, tmp, size); + /* + * Before releasing other threads, must ensure the copy + * back to + */ + asm volatile("sync" ::: "memory"); + mprotect(map1, size, PROT_READ|PROT_WRITE); + asm volatile("sync" ::: "memory"); + segv_wait = 0; + + usleep(1); /* This value makes a big difference */ + } + + return 0; +} + +void alrm_sighandler(int sig) +{ + timeout = 1; +} + +int main(int argc, char *argv[]) +{ + int c; + int page_size = getpagesize(); + time_t now; + int i, dir_error; + pthread_attr_t attr; + key_t shm_key = (key_t) getpid(); + int shmid, run_time = 20 * 60; + struct sigaction sa_alrm; + + snprintf(logdir, LOGDIR_NAME_SIZE, + "/tmp/logdir-%u", (unsigned int)getpid()); + while ((c = getopt(argc, argv, "r:hn:l:t:")) != -1) { + switch(c) { + case 'r': + start_cpu = strtoul(optarg, NULL, 10); + break; + case 'h': + printf("%s [-r <start_cpu>] [-n <nrthreads>] [-l <logdir>] [-t <timeout>]\n", argv[0]); + exit(0); + break; + case 'n': + nrthreads = strtoul(optarg, NULL, 10); + break; + case 'l': + strncpy(logdir, optarg, LOGDIR_NAME_SIZE); + break; + case 't': + run_time = strtoul(optarg, NULL, 10); + break; + default: + printf("invalid option\n"); + exit(0); + break; + } + } + + if (nrthreads > MAX_THREADS) + nrthreads = MAX_THREADS; + + shmid = shmget(shm_key, page_size, IPC_CREAT|0666); + if (shmid < 0) { + err_msg("Failed shmget\n"); + } + + map1 = shmat(shmid, NULL, 0); + if (map1 == (void *) -1) { + err_msg("Failed shmat"); + } + + map2 = shmat(shmid, NULL, 0); + if (map2 == (void *) -1) { + err_msg("Failed shmat"); + } + + dir_error = mkdir(logdir, 0755); + + if (dir_error) { + err_msg("Failed mkdir"); + } + + printf("start_cpu list:%lu\n", start_cpu); + printf("number of worker threads:%lu + 1 snapshot thread\n", nrthreads); + printf("Allocated address:0x%016lx + secondary map:0x%016lx\n", (unsigned long)map1, (unsigned long)map2); + printf("logdir at : %s\n", logdir); + printf("Timeout: %d seconds\n", run_time); + + time(&now); + printf("=================================\n"); + printf(" Starting Test\n"); + printf(" %s", ctime(&now)); + printf("=================================\n"); + + for (i = 0; i < nrthreads; i++) { + if (1 && !fork()) { + prctl(PR_SET_PDEATHSIG, SIGKILL); + set_mycpu(start_cpu + i); + for (;;) + sched_yield(); + exit(0); + } + } + + + sa_alrm.sa_handler = &alrm_sighandler; + sigemptyset(&sa_alrm.sa_mask); + sa_alrm.sa_flags = 0; + + if (sigaction(SIGALRM, &sa_alrm, 0) == -1) { + err_msg("Failed signal handler registration\n"); + } + + alarm(run_time); + + pthread_attr_init(&attr); + for (i = 0; i < nrthreads; i++) { + rim_thread_ids[i] = i; + pthread_create(&rim_threads[i], &attr, rim_fn, &rim_thread_ids[i]); + set_pthread_cpu(rim_threads[i], start_cpu + i); + } + + pthread_create(&mem_snapshot_thread, &attr, mem_snapshot_fn, map1); + set_pthread_cpu(mem_snapshot_thread, start_cpu + i); + + + pthread_join(mem_snapshot_thread, NULL); + for (i = 0; i < nrthreads; i++) { + pthread_join(rim_threads[i], NULL); + } + + if (!timeout) { + time(&now); + printf("=================================\n"); + printf(" Data Corruption Detected\n"); + printf(" %s", ctime(&now)); + printf(" See logfiles in %s\n", logdir); + printf("=================================\n"); + return 1; + } + return 0; +} diff --git a/tools/testing/selftests/powerpc/ptrace/.gitignore b/tools/testing/selftests/powerpc/ptrace/.gitignore index 07ec449a2767..dce19f221c46 100644 --- a/tools/testing/selftests/powerpc/ptrace/.gitignore +++ b/tools/testing/selftests/powerpc/ptrace/.gitignore @@ -10,3 +10,6 @@ ptrace-tm-spd-vsx ptrace-tm-spr ptrace-hwbreak perf-hwbreak +core-pkey +ptrace-pkey +ptrace-syscall diff --git a/tools/testing/selftests/powerpc/security/.gitignore b/tools/testing/selftests/powerpc/security/.gitignore new file mode 100644 index 000000000000..0b969fba3beb --- /dev/null +++ b/tools/testing/selftests/powerpc/security/.gitignore @@ -0,0 +1 @@ +rfi_flush diff --git a/tools/testing/selftests/powerpc/stringloops/.gitignore b/tools/testing/selftests/powerpc/stringloops/.gitignore index 0b43da74ee46..31a17e0ba884 100644 --- a/tools/testing/selftests/powerpc/stringloops/.gitignore +++ b/tools/testing/selftests/powerpc/stringloops/.gitignore @@ -1 +1,4 @@ -memcmp +memcmp_64 +memcmp_32 +strlen +strlen_32 diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 951fe855f7cd..98f2708d86cc 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -17,3 +17,4 @@ tm-vmx-unavail tm-unavailable tm-trap tm-sigreturn +tm-poison diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index c0734ed0ef56..b15a1a325bd0 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -5,7 +5,7 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-unavailable tm-trap \ $(SIGNAL_CONTEXT_CHK_TESTS) tm-sigreturn tm-signal-sigreturn-nt \ - tm-signal-context-force-tm + tm-signal-context-force-tm tm-poison top_srcdir = ../../../../.. include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/tm/tm-poison.c b/tools/testing/selftests/powerpc/tm/tm-poison.c new file mode 100644 index 000000000000..977558497c16 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-poison.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2019, Gustavo Romero, Michael Neuling, IBM Corp. + * + * This test will spawn two processes. Both will be attached to the same + * CPU (CPU 0). The child will be in a loop writing to FP register f31 and + * VMX/VEC/Altivec register vr31 a known value, called poison, calling + * sched_yield syscall after to allow the parent to switch on the CPU. + * Parent will set f31 and vr31 to 1 and in a loop will check if f31 and + * vr31 remain 1 as expected until a given timeout (2m). If the issue is + * present child's poison will leak into parent's f31 or vr31 registers, + * otherwise, poison will never leak into parent's f31 and vr31 registers. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <inttypes.h> +#include <sched.h> +#include <sys/types.h> +#include <signal.h> +#include <inttypes.h> + +#include "tm.h" + +int tm_poison_test(void) +{ + int pid; + cpu_set_t cpuset; + uint64_t poison = 0xdeadbeefc0dec0fe; + uint64_t unknown = 0; + bool fail_fp = false; + bool fail_vr = false; + + SKIP_IF(!have_htm()); + + /* Attach both Child and Parent to CPU 0 */ + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + sched_setaffinity(0, sizeof(cpuset), &cpuset); + + pid = fork(); + if (!pid) { + /** + * child + */ + while (1) { + sched_yield(); + asm ( + "mtvsrd 31, %[poison];" // f31 = poison + "mtvsrd 63, %[poison];" // vr31 = poison + + : : [poison] "r" (poison) : ); + } + } + + /** + * parent + */ + asm ( + /* + * Set r3, r4, and f31 to known value 1 before entering + * in transaction. They won't be written after that. + */ + " li 3, 0x1 ;" + " li 4, 0x1 ;" + " mtvsrd 31, 4 ;" + + /* + * The Time Base (TB) is a 64-bit counter register that is + * independent of the CPU clock and which is incremented + * at a frequency of 512000000 Hz, so every 1.953125ns. + * So it's necessary 120s/0.000000001953125s = 61440000000 + * increments to get a 2 minutes timeout. Below we set that + * value in r5 and then use r6 to track initial TB value, + * updating TB values in r7 at every iteration and comparing it + * to r6. When r7 (current) - r6 (initial) > 61440000000 we bail + * out since for sure we spent already 2 minutes in the loop. + * SPR 268 is the TB register. + */ + " lis 5, 14 ;" + " ori 5, 5, 19996 ;" + " sldi 5, 5, 16 ;" // r5 = 61440000000 + + " mfspr 6, 268 ;" // r6 (TB initial) + "1: mfspr 7, 268 ;" // r7 (TB current) + " subf 7, 6, 7 ;" // r7 - r6 > 61440000000 ? + " cmpd 7, 5 ;" + " bgt 3f ;" // yes, exit + + /* + * Main loop to check f31 + */ + " tbegin. ;" // no, try again + " beq 1b ;" // restart if no timeout + " mfvsrd 3, 31 ;" // read f31 + " cmpd 3, 4 ;" // f31 == 1 ? + " bne 2f ;" // broken :-( + " tabort. 3 ;" // try another transaction + "2: tend. ;" // commit transaction + "3: mr %[unknown], 3 ;" // record r3 + + : [unknown] "=r" (unknown) + : + : "cr0", "r3", "r4", "r5", "r6", "r7", "vs31" + + ); + + /* + * On leak 'unknown' will contain 'poison' value from child, + * otherwise (no leak) 'unknown' will contain the same value + * as r3 before entering in transactional mode, i.e. 0x1. + */ + fail_fp = unknown != 0x1; + if (fail_fp) + printf("Unknown value %#"PRIx64" leaked into f31!\n", unknown); + else + printf("Good, no poison or leaked value into FP registers\n"); + + asm ( + /* + * Set r3, r4, and vr31 to known value 1 before entering + * in transaction. They won't be written after that. + */ + " li 3, 0x1 ;" + " li 4, 0x1 ;" + " mtvsrd 63, 4 ;" + + " lis 5, 14 ;" + " ori 5, 5, 19996 ;" + " sldi 5, 5, 16 ;" // r5 = 61440000000 + + " mfspr 6, 268 ;" // r6 (TB initial) + "1: mfspr 7, 268 ;" // r7 (TB current) + " subf 7, 6, 7 ;" // r7 - r6 > 61440000000 ? + " cmpd 7, 5 ;" + " bgt 3f ;" // yes, exit + + /* + * Main loop to check vr31 + */ + " tbegin. ;" // no, try again + " beq 1b ;" // restart if no timeout + " mfvsrd 3, 63 ;" // read vr31 + " cmpd 3, 4 ;" // vr31 == 1 ? + " bne 2f ;" // broken :-( + " tabort. 3 ;" // try another transaction + "2: tend. ;" // commit transaction + "3: mr %[unknown], 3 ;" // record r3 + + : [unknown] "=r" (unknown) + : + : "cr0", "r3", "r4", "r5", "r6", "r7", "vs63" + + ); + + /* + * On leak 'unknown' will contain 'poison' value from child, + * otherwise (no leak) 'unknown' will contain the same value + * as r3 before entering in transactional mode, i.e. 0x1. + */ + fail_vr = unknown != 0x1; + if (fail_vr) + printf("Unknown value %#"PRIx64" leaked into vr31!\n", unknown); + else + printf("Good, no poison or leaked value into VEC registers\n"); + + kill(pid, SIGKILL); + + return (fail_fp | fail_vr); +} + +int main(int argc, char *argv[]) +{ + /* Test completes in about 4m */ + test_harness_set_timeout(250); + return test_harness(tm_poison_test, "tm_poison_test"); +} diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c index d57c2d2ab6ec..254f912ad611 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c @@ -5,10 +5,11 @@ * Test the kernel's signal frame code. * * The kernel sets up two sets of ucontexts if the signal was to be - * delivered while the thread was in a transaction. + * delivered while the thread was in a transaction (referred too as + * first and second contexts). * Expected behaviour is that the checkpointed state is in the user - * context passed to the signal handler. The speculated state can be - * accessed with the uc_link pointer. + * context passed to the signal handler (first context). The speculated + * state can be accessed with the uc_link pointer (second context). * * The rationale for this is that if TM unaware code (which linked * against TM libs) installs a signal handler it will not know of the @@ -28,17 +29,20 @@ #define MAX_ATTEMPT 500000 -#define NV_FPU_REGS 18 +#define NV_FPU_REGS 18 /* Number of non-volatile FP registers */ +#define FPR14 14 /* First non-volatile FP register to check in f14-31 subset */ long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); -/* Be sure there are 2x as many as there are NV FPU regs (2x18) */ +/* Test only non-volatile registers, i.e. 18 fpr registers from f14 to f31 */ static double fps[] = { + /* First context will be set with these values, i.e. non-speculative */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + /* Second context will be set with these values, i.e. speculative */ -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18 }; -static sig_atomic_t fail; +static sig_atomic_t fail, broken; static void signal_usr1(int signum, siginfo_t *info, void *uc) { @@ -46,11 +50,24 @@ static void signal_usr1(int signum, siginfo_t *info, void *uc) ucontext_t *ucp = uc; ucontext_t *tm_ucp = ucp->uc_link; - for (i = 0; i < NV_FPU_REGS && !fail; i++) { - fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]); - fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]); - if (fail) - printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]); + for (i = 0; i < NV_FPU_REGS; i++) { + /* Check first context. Print all mismatches. */ + fail = (ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[i]); + if (fail) { + broken = 1; + printf("FPR%d (1st context) == %g instead of %g (expected)\n", + FPR14 + i, ucp->uc_mcontext.fp_regs[FPR14 + i], fps[i]); + } + } + + for (i = 0; i < NV_FPU_REGS; i++) { + /* Check second context. Print all mismatches. */ + fail = (tm_ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[NV_FPU_REGS + i]); + if (fail) { + broken = 1; + printf("FPR%d (2nd context) == %g instead of %g (expected)\n", + FPR14 + i, tm_ucp->uc_mcontext.fp_regs[FPR14 + i], fps[NV_FPU_REGS + i]); + } } } @@ -72,13 +89,19 @@ static int tm_signal_context_chk_fpu() } i = 0; - while (i < MAX_ATTEMPT && !fail) { + while (i < MAX_ATTEMPT && !broken) { + /* + * tm_signal_self_context_load will set both first and second + * contexts accordingly to the values passed through non-NULL + * array pointers to it, in that case 'fps', and invoke the + * signal handler installed for SIGUSR1. + */ rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL); FAIL_IF(rc != pid); i++; } - return fail; + return (broken); } int main(void) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c index 4d05f8b0254c..0cc680f61828 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c @@ -5,10 +5,11 @@ * Test the kernel's signal frame code. * * The kernel sets up two sets of ucontexts if the signal was to be - * delivered while the thread was in a transaction. + * delivered while the thread was in a transaction (referred too as + * first and second contexts). * Expected behaviour is that the checkpointed state is in the user - * context passed to the signal handler. The speculated state can be - * accessed with the uc_link pointer. + * context passed to the signal handler (first context). The speculated + * state can be accessed with the uc_link pointer (second context). * * The rationale for this is that if TM unaware code (which linked * against TM libs) installs a signal handler it will not know of the @@ -28,14 +29,22 @@ #define MAX_ATTEMPT 500000 -#define NV_GPR_REGS 18 +#define NV_GPR_REGS 18 /* Number of non-volatile GPR registers */ +#define R14 14 /* First non-volatile register to check in r14-r31 subset */ long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); -static sig_atomic_t fail; +static sig_atomic_t fail, broken; -static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18}; +/* Test only non-volatile general purpose registers, i.e. r14-r31 */ +static long gprs[] = { + /* First context will be set with these values, i.e. non-speculative */ + /* R14, R15, ... */ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + /* Second context will be set with these values, i.e. speculative */ + /* R14, R15, ... */ + -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18 +}; static void signal_usr1(int signum, siginfo_t *info, void *uc) { @@ -43,12 +52,24 @@ static void signal_usr1(int signum, siginfo_t *info, void *uc) ucontext_t *ucp = uc; ucontext_t *tm_ucp = ucp->uc_link; - for (i = 0; i < NV_GPR_REGS && !fail; i++) { - fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]); - fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]); - if (fail) - printf("Failed on %d GPR %lu or %lu\n", i, - ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]); + /* Check first context. Print all mismatches. */ + for (i = 0; i < NV_GPR_REGS; i++) { + fail = (ucp->uc_mcontext.gp_regs[R14 + i] != gprs[i]); + if (fail) { + broken = 1; + printf("GPR%d (1st context) == %lu instead of %lu (expected)\n", + R14 + i, ucp->uc_mcontext.gp_regs[R14 + i], gprs[i]); + } + } + + /* Check second context. Print all mismatches. */ + for (i = 0; i < NV_GPR_REGS; i++) { + fail = (tm_ucp->uc_mcontext.gp_regs[R14 + i] != gprs[NV_GPR_REGS + i]); + if (fail) { + broken = 1; + printf("GPR%d (2nd context) == %lu instead of %lu (expected)\n", + R14 + i, tm_ucp->uc_mcontext.gp_regs[R14 + i], gprs[NV_GPR_REGS + i]); + } } } @@ -70,13 +91,19 @@ static int tm_signal_context_chk_gpr() } i = 0; - while (i < MAX_ATTEMPT && !fail) { - rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL); + while (i < MAX_ATTEMPT && !broken) { + /* + * tm_signal_self_context_load will set both first and second + * contexts accordingly to the values passed through non-NULL + * array pointers to it, in that case 'gprs', and invoke the + * signal handler installed for SIGUSR1. + */ + rc = tm_signal_self_context_load(pid, gprs, NULL, NULL, NULL); FAIL_IF(rc != pid); i++; } - return fail; + return broken; } int main(void) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c index 48ad01499b1a..b6d52730a0d8 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c @@ -5,10 +5,11 @@ * Test the kernel's signal frame code. * * The kernel sets up two sets of ucontexts if the signal was to be - * delivered while the thread was in a transaction. + * delivered while the thread was in a transaction (referred too as + * first and second contexts). * Expected behaviour is that the checkpointed state is in the user - * context passed to the signal handler. The speculated state can be - * accessed with the uc_link pointer. + * context passed to the signal handler (first context). The speculated + * state can be accessed with the uc_link pointer (second context). * * The rationale for this is that if TM unaware code (which linked * against TM libs) installs a signal handler it will not know of the @@ -29,18 +30,24 @@ #define MAX_ATTEMPT 500000 -#define NV_VMX_REGS 12 +#define NV_VMX_REGS 12 /* Number of non-volatile VMX registers */ +#define VMX20 20 /* First non-volatile register to check in vr20-31 subset */ long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); -static sig_atomic_t fail; +static sig_atomic_t fail, broken; +/* Test only non-volatile registers, i.e. 12 vmx registers from vr20 to vr31 */ vector int vms[] = { - {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12}, + /* First context will be set with these values, i.e. non-speculative */ + /* VMX20 , VMX21 , ... */ + { 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12}, {13,14,15,16},{17,18,19,20},{21,22,23,24}, {25,26,27,28},{29,30,31,32},{33,34,35,36}, {37,38,39,40},{41,42,43,44},{45,46,47,48}, - {-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12}, + /* Second context will be set with these values, i.e. speculative */ + /* VMX20 , VMX21 , ... */ + { -1, -2, -3, -4},{ -5, -6, -7, -8},{ -9,-10,-11,-12}, {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24}, {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36}, {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48} @@ -48,26 +55,43 @@ vector int vms[] = { static void signal_usr1(int signum, siginfo_t *info, void *uc) { - int i; + int i, j; ucontext_t *ucp = uc; ucontext_t *tm_ucp = ucp->uc_link; - for (i = 0; i < NV_VMX_REGS && !fail; i++) { - fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20], + for (i = 0; i < NV_VMX_REGS; i++) { + /* Check first context. Print all mismatches. */ + fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[VMX20 + i], &vms[i], sizeof(vector int)); - fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20], - &vms[i + NV_VMX_REGS], sizeof (vector int)); - if (fail) { - int j; + broken = 1; + printf("VMX%d (1st context) == 0x", VMX20 + i); + /* Print actual value in first context. */ + for (j = 0; j < 4; j++) + printf("%08x", ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]); + printf(" instead of 0x"); + /* Print expected value. */ + for (j = 0; j < 4; j++) + printf("%08x", vms[i][j]); + printf(" (expected)\n"); + } + } - fprintf(stderr, "Failed on %d vmx 0x", i); + for (i = 0; i < NV_VMX_REGS; i++) { + /* Check second context. Print all mismatches. */ + fail = memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i], + &vms[NV_VMX_REGS + i], sizeof (vector int)); + if (fail) { + broken = 1; + printf("VMX%d (2nd context) == 0x", NV_VMX_REGS + i); + /* Print actual value in second context. */ + for (j = 0; j < 4; j++) + printf("%08x", tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]); + printf(" instead of 0x"); + /* Print expected value. */ for (j = 0; j < 4; j++) - fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]); - fprintf(stderr, " vs 0x"); - for (j = 0 ; j < 4; j++) - fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]); - fprintf(stderr, "\n"); + printf("%08x", vms[NV_VMX_REGS + i][j]); + printf(" (expected)\n"); } } } @@ -90,13 +114,19 @@ static int tm_signal_context_chk() } i = 0; - while (i < MAX_ATTEMPT && !fail) { + while (i < MAX_ATTEMPT && !broken) { + /* + * tm_signal_self_context_load will set both first and second + * contexts accordingly to the values passed through non-NULL + * array pointers to it, in that case 'vms', and invoke the + * signal handler installed for SIGUSR1. + */ rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL); FAIL_IF(rc != pid); i++; } - return fail; + return (broken); } int main(void) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c index 8c8677a408bb..8e25e2072ecd 100644 --- a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c @@ -5,10 +5,11 @@ * Test the kernel's signal frame code. * * The kernel sets up two sets of ucontexts if the signal was to be - * delivered while the thread was in a transaction. + * delivered while the thread was in a transaction (referred too as + * first and second contexts). * Expected behaviour is that the checkpointed state is in the user - * context passed to the signal handler. The speculated state can be - * accessed with the uc_link pointer. + * context passed to the signal handler (first context). The speculated + * state can be accessed with the uc_link pointer (second context). * * The rationale for this is that if TM unaware code (which linked * against TM libs) installs a signal handler it will not know of the @@ -29,17 +30,24 @@ #define MAX_ATTEMPT 500000 -#define NV_VSX_REGS 12 +#define NV_VSX_REGS 12 /* Number of VSX registers to check. */ +#define VSX20 20 /* First VSX register to check in vsr20-vsr31 subset */ +#define FPR20 20 /* FPR20 overlaps VSX20 most significant doubleword */ long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); -static sig_atomic_t fail; +static sig_atomic_t fail, broken; -vector int vss[] = { - {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12}, +/* Test only 12 vsx registers from vsr20 to vsr31 */ +vector int vsxs[] = { + /* First context will be set with these values, i.e. non-speculative */ + /* VSX20 , VSX21 , ... */ + { 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12}, {13,14,15,16},{17,18,19,20},{21,22,23,24}, {25,26,27,28},{29,30,31,32},{33,34,35,36}, {37,38,39,40},{41,42,43,44},{45,46,47,48}, + /* Second context will be set with these values, i.e. speculative */ + /* VSX20 , VSX21 , ... */ {-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12}, {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24}, {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36}, @@ -48,41 +56,91 @@ vector int vss[] = { static void signal_usr1(int signum, siginfo_t *info, void *uc) { - int i; - uint8_t vsc[sizeof(vector int)]; - uint8_t vst[sizeof(vector int)]; + int i, j; + uint8_t vsx[sizeof(vector int)]; + uint8_t vsx_tm[sizeof(vector int)]; ucontext_t *ucp = uc; ucontext_t *tm_ucp = ucp->uc_link; /* - * The other half of the VSX regs will be after v_regs. + * FP registers and VMX registers overlap the VSX registers. + * + * FP registers (f0-31) overlap the most significant 64 bits of VSX + * registers vsr0-31, whilst VMX registers vr0-31, being 128-bit like + * the VSX registers, overlap fully the other half of VSX registers, + * i.e. vr0-31 overlaps fully vsr32-63. + * + * Due to compatibility and historical reasons (VMX/Altivec support + * appeared first on the architecture), VMX registers vr0-31 (so VSX + * half vsr32-63 too) are stored right after the v_regs pointer, in an + * area allocated for 'vmx_reverse' array (please see + * arch/powerpc/include/uapi/asm/sigcontext.h for details about the + * mcontext_t structure on Power). + * + * The other VSX half (vsr0-31) is hence stored below vr0-31/vsr32-63 + * registers, but only the least significant 64 bits of vsr0-31. The + * most significant 64 bits of vsr0-31 (f0-31), as it overlaps the FP + * registers, is kept in fp_regs. + * + * v_regs is a 16 byte aligned pointer at the start of vmx_reserve + * (vmx_reserve may or may not be 16 aligned) where the v_regs structure + * exists, so v_regs points to where vr0-31 / vsr32-63 registers are + * fully stored. Since v_regs type is elf_vrregset_t, v_regs + 1 + * skips all the slots used to store vr0-31 / vsr32-64 and points to + * part of one VSX half, i.e. v_regs + 1 points to the least significant + * 64 bits of vsr0-31. The other part of this half (the most significant + * part of vsr0-31) is stored in fp_regs. * - * In short, vmx_reserve array holds everything. v_regs is a 16 - * byte aligned pointer at the start of vmx_reserve (vmx_reserve - * may or may not be 16 aligned) where the v_regs structure exists. - * (half of) The VSX regsters are directly after v_regs so the - * easiest way to find them below. */ + /* Get pointer to least significant doubleword of vsr0-31 */ long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1); long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1); - for (i = 0; i < NV_VSX_REGS && !fail; i++) { - memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8); - memcpy(vsc + 8, &vsx_ptr[20 + i], 8); - fail = memcmp(vsc, &vss[i], sizeof(vector int)); - memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8); - memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8); - fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int)); - if (fail) { - int j; + /* Check first context. Print all mismatches. */ + for (i = 0; i < NV_VSX_REGS; i++) { + /* + * Copy VSX most significant doubleword from fp_regs and + * copy VSX least significant one from 64-bit slots below + * saved VMX registers. + */ + memcpy(vsx, &ucp->uc_mcontext.fp_regs[FPR20 + i], 8); + memcpy(vsx + 8, &vsx_ptr[VSX20 + i], 8); + + fail = memcmp(vsx, &vsxs[i], sizeof(vector int)); - fprintf(stderr, "Failed on %d vsx 0x", i); + if (fail) { + broken = 1; + printf("VSX%d (1st context) == 0x", VSX20 + i); for (j = 0; j < 16; j++) - fprintf(stderr, "%02x", vsc[j]); - fprintf(stderr, " vs 0x"); + printf("%02x", vsx[j]); + printf(" instead of 0x"); + for (j = 0; j < 4; j++) + printf("%08x", vsxs[i][j]); + printf(" (expected)\n"); + } + } + + /* Check second context. Print all mismatches. */ + for (i = 0; i < NV_VSX_REGS; i++) { + /* + * Copy VSX most significant doubleword from fp_regs and + * copy VSX least significant one from 64-bit slots below + * saved VMX registers. + */ + memcpy(vsx_tm, &tm_ucp->uc_mcontext.fp_regs[FPR20 + i], 8); + memcpy(vsx_tm + 8, &tm_vsx_ptr[VSX20 + i], 8); + + fail = memcmp(vsx_tm, &vsxs[NV_VSX_REGS + i], sizeof(vector int)); + + if (fail) { + broken = 1; + printf("VSX%d (2nd context) == 0x", VSX20 + i); for (j = 0; j < 16; j++) - fprintf(stderr, "%02x", vst[j]); - fprintf(stderr, "\n"); + printf("%02x", vsx_tm[j]); + printf(" instead of 0x"); + for (j = 0; j < 4; j++) + printf("%08x", vsxs[NV_VSX_REGS + i][j]); + printf("(expected)\n"); } } } @@ -105,13 +163,19 @@ static int tm_signal_context_chk() } i = 0; - while (i < MAX_ATTEMPT && !fail) { - rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss); + while (i < MAX_ATTEMPT && !broken) { + /* + * tm_signal_self_context_load will set both first and second + * contexts accordingly to the values passed through non-NULL + * array pointers to it, in that case 'vsxs', and invoke the + * signal handler installed for SIGUSR1. + */ + rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vsxs); FAIL_IF(rc != pid); i++; } - return fail; + return (broken); } int main(void) diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h index 97f9f491c541..c402464b038f 100644 --- a/tools/testing/selftests/powerpc/tm/tm.h +++ b/tools/testing/selftests/powerpc/tm/tm.h @@ -55,7 +55,8 @@ static inline bool failure_is_unavailable(void) static inline bool failure_is_reschedule(void) { if ((failure_code() & TM_CAUSE_RESCHED) == TM_CAUSE_RESCHED || - (failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED) + (failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED || + (failure_code() & TM_CAUSE_KVM_FAC_UNAV) == TM_CAUSE_KVM_FAC_UNAV) return true; return false; diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 6ef7f16c4cf5..7f8b5c8982e3 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -199,6 +199,11 @@ struct seccomp_notif_sizes { }; #endif +#ifndef PTRACE_EVENTMSG_SYSCALL_ENTRY +#define PTRACE_EVENTMSG_SYSCALL_ENTRY 1 +#define PTRACE_EVENTMSG_SYSCALL_EXIT 2 +#endif + #ifndef seccomp int seccomp(unsigned int op, unsigned int flags, void *args) { diff --git a/tools/testing/selftests/tpm2/Makefile b/tools/testing/selftests/tpm2/Makefile index 9dd848427a7b..1a5db1eb8ed5 100644 --- a/tools/testing/selftests/tpm2/Makefile +++ b/tools/testing/selftests/tpm2/Makefile @@ -2,3 +2,4 @@ include ../lib.mk TEST_PROGS := test_smoke.sh test_space.sh +TEST_PROGS_EXTENDED := tpm2.py tpm2_tests.py diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c index c2333c78cf04..afff120c7be6 100644 --- a/tools/testing/selftests/watchdog/watchdog-test.c +++ b/tools/testing/selftests/watchdog/watchdog-test.c @@ -19,7 +19,7 @@ int fd; const char v = 'V'; -static const char sopts[] = "bdehp:t:Tn:NL"; +static const char sopts[] = "bdehp:t:Tn:NLf:"; static const struct option lopts[] = { {"bootstatus", no_argument, NULL, 'b'}, {"disable", no_argument, NULL, 'd'}, @@ -31,6 +31,7 @@ static const struct option lopts[] = { {"pretimeout", required_argument, NULL, 'n'}, {"getpretimeout", no_argument, NULL, 'N'}, {"gettimeleft", no_argument, NULL, 'L'}, + {"file", required_argument, NULL, 'f'}, {NULL, no_argument, NULL, 0x0} }; @@ -69,16 +70,19 @@ static void term(int sig) static void usage(char *progname) { printf("Usage: %s [options]\n", progname); - printf(" -b, --bootstatus Get last boot status (Watchdog/POR)\n"); - printf(" -d, --disable Turn off the watchdog timer\n"); - printf(" -e, --enable Turn on the watchdog timer\n"); - printf(" -h, --help Print the help message\n"); - printf(" -p, --pingrate=P Set ping rate to P seconds (default %d)\n", DEFAULT_PING_RATE); - printf(" -t, --timeout=T Set timeout to T seconds\n"); - printf(" -T, --gettimeout Get the timeout\n"); - printf(" -n, --pretimeout=T Set the pretimeout to T seconds\n"); - printf(" -N, --getpretimeout Get the pretimeout\n"); - printf(" -L, --gettimeleft Get the time left until timer expires\n"); + printf(" -f, --file\t\tOpen watchdog device file\n"); + printf("\t\t\tDefault is /dev/watchdog\n"); + printf(" -b, --bootstatus\tGet last boot status (Watchdog/POR)\n"); + printf(" -d, --disable\t\tTurn off the watchdog timer\n"); + printf(" -e, --enable\t\tTurn on the watchdog timer\n"); + printf(" -h, --help\t\tPrint the help message\n"); + printf(" -p, --pingrate=P\tSet ping rate to P seconds (default %d)\n", + DEFAULT_PING_RATE); + printf(" -t, --timeout=T\tSet timeout to T seconds\n"); + printf(" -T, --gettimeout\tGet the timeout\n"); + printf(" -n, --pretimeout=T\tSet the pretimeout to T seconds\n"); + printf(" -N, --getpretimeout\tGet the pretimeout\n"); + printf(" -L, --gettimeleft\tGet the time left until timer expires\n"); printf("\n"); printf("Parameters are parsed left-to-right in real-time.\n"); printf("Example: %s -d -t 10 -p 5 -e\n", progname); @@ -92,14 +96,20 @@ int main(int argc, char *argv[]) int ret; int c; int oneshot = 0; + char *file = "/dev/watchdog"; setbuf(stdout, NULL); - fd = open("/dev/watchdog", O_WRONLY); + while ((c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { + if (c == 'f') + file = optarg; + } + + fd = open(file, O_WRONLY); if (fd == -1) { if (errno == ENOENT) - printf("Watchdog device not enabled.\n"); + printf("Watchdog device (%s) not found.\n", file); else if (errno == EACCES) printf("Run watchdog as root.\n"); else @@ -108,6 +118,8 @@ int main(int argc, char *argv[]) exit(-1); } + optind = 0; + while ((c = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { switch (c) { case 'b': @@ -190,6 +202,9 @@ int main(int argc, char *argv[]) else printf("WDIOC_GETTIMELEFT error '%s'\n", strerror(errno)); break; + case 'f': + /* Handled above */ + break; default: usage(argv[0]); |