Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'perf-core-for-mingo-5.0-20190121' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

BPF:

Song Liu:

- Introduce PERF_RECORD_KSYMBOL to allow tooling to notice the addition
of new kernel symbols and be able to resolve samples in such symbols.

- Introduce PERF_RECORD_BPF_EVENT to notify tooling about the loading
and unloading of BPF programs, making them visible and allowing for
the request of further information to allow for things like annotation.

- Change the userspace perf tools to handle those new events and to
synthesize them for pre-existing loaded BPF programs.

Kernel:

Arnaldo Carvalho de Melo:

- Make perf_event_output() propagate the output() return, allowing
users to check for -ENOSPC in the ring buffer.

perf report:

Thomas Richter:

- Display arch specific diagnostic counter sets, starting with s390
diagnostic counter sets.

perf session:

Jiri Olsa:

- Introduce a reader object to prep for multithreaded processing
of recorded events.

Misc:

Rasmus Villemoes:

- Replace automatic const char[] variables by statics, to avoid
initializing them at runtime, instead having them in .rodata,
reducing code size.

YueHaibing:

- Remove duplicated workqueue.h include from perf_event.h

Brajeswar Ghosh:

- Remove some more duplicated headers.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>

+1358 -125
+7
include/linux/filter.h
··· 951 951 952 952 void bpf_prog_kallsyms_add(struct bpf_prog *fp); 953 953 void bpf_prog_kallsyms_del(struct bpf_prog *fp); 954 + void bpf_get_prog_name(const struct bpf_prog *prog, char *sym); 954 955 955 956 #else /* CONFIG_BPF_JIT */ 956 957 ··· 1007 1006 static inline void bpf_prog_kallsyms_del(struct bpf_prog *fp) 1008 1007 { 1009 1008 } 1009 + 1010 + static inline void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) 1011 + { 1012 + sym[0] = '\0'; 1013 + } 1014 + 1010 1015 #endif /* CONFIG_BPF_JIT */ 1011 1016 1012 1017 void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp);
+17 -4
include/linux/perf_event.h
··· 53 53 #include <linux/atomic.h> 54 54 #include <linux/sysfs.h> 55 55 #include <linux/perf_regs.h> 56 - #include <linux/workqueue.h> 57 56 #include <linux/cgroup.h> 58 57 #include <asm/local.h> 59 58 ··· 978 979 extern void perf_event_output_backward(struct perf_event *event, 979 980 struct perf_sample_data *data, 980 981 struct pt_regs *regs); 981 - extern void perf_event_output(struct perf_event *event, 982 - struct perf_sample_data *data, 983 - struct pt_regs *regs); 982 + extern int perf_event_output(struct perf_event *event, 983 + struct perf_sample_data *data, 984 + struct pt_regs *regs); 984 985 985 986 static inline bool 986 987 is_default_overflow_handler(struct perf_event *event) ··· 1122 1123 } 1123 1124 1124 1125 extern void perf_event_mmap(struct vm_area_struct *vma); 1126 + 1127 + extern void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, 1128 + bool unregister, const char *sym); 1129 + extern void perf_event_bpf_event(struct bpf_prog *prog, 1130 + enum perf_bpf_event_type type, 1131 + u16 flags); 1132 + 1125 1133 extern struct perf_guest_info_callbacks *perf_guest_cbs; 1126 1134 extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); 1127 1135 extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); ··· 1349 1343 (struct perf_guest_info_callbacks *callbacks) { return 0; } 1350 1344 1351 1345 static inline void perf_event_mmap(struct vm_area_struct *vma) { } 1346 + 1347 + typedef int (perf_ksymbol_get_name_f)(char *name, int name_len, void *data); 1348 + static inline void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, 1349 + bool unregister, const char *sym) { } 1350 + static inline void perf_event_bpf_event(struct bpf_prog *prog, 1351 + enum perf_bpf_event_type type, 1352 + u16 flags) { } 1352 1353 static inline void perf_event_exec(void) { } 1353 1354 static inline void perf_event_comm(struct task_struct *tsk, bool exec) { } 1354 1355 static inline void perf_event_namespaces(struct task_struct *tsk) { }
+52 -1
include/uapi/linux/perf_event.h
··· 372 372 context_switch : 1, /* context switch data */ 373 373 write_backward : 1, /* Write ring buffer from end to beginning */ 374 374 namespaces : 1, /* include namespaces data */ 375 - __reserved_1 : 35; 375 + ksymbol : 1, /* include ksymbol events */ 376 + bpf_event : 1, /* include bpf events */ 377 + __reserved_1 : 33; 376 378 377 379 union { 378 380 __u32 wakeup_events; /* wakeup every n events */ ··· 965 963 */ 966 964 PERF_RECORD_NAMESPACES = 16, 967 965 966 + /* 967 + * Record ksymbol register/unregister events: 968 + * 969 + * struct { 970 + * struct perf_event_header header; 971 + * u64 addr; 972 + * u32 len; 973 + * u16 ksym_type; 974 + * u16 flags; 975 + * char name[]; 976 + * struct sample_id sample_id; 977 + * }; 978 + */ 979 + PERF_RECORD_KSYMBOL = 17, 980 + 981 + /* 982 + * Record bpf events: 983 + * enum perf_bpf_event_type { 984 + * PERF_BPF_EVENT_UNKNOWN = 0, 985 + * PERF_BPF_EVENT_PROG_LOAD = 1, 986 + * PERF_BPF_EVENT_PROG_UNLOAD = 2, 987 + * }; 988 + * 989 + * struct { 990 + * struct perf_event_header header; 991 + * u16 type; 992 + * u16 flags; 993 + * u32 id; 994 + * u8 tag[BPF_TAG_SIZE]; 995 + * struct sample_id sample_id; 996 + * }; 997 + */ 998 + PERF_RECORD_BPF_EVENT = 18, 999 + 968 1000 PERF_RECORD_MAX, /* non-ABI */ 1001 + }; 1002 + 1003 + enum perf_record_ksymbol_type { 1004 + PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0, 1005 + PERF_RECORD_KSYMBOL_TYPE_BPF = 1, 1006 + PERF_RECORD_KSYMBOL_TYPE_MAX /* non-ABI */ 1007 + }; 1008 + 1009 + #define PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER (1 << 0) 1010 + 1011 + enum perf_bpf_event_type { 1012 + PERF_BPF_EVENT_UNKNOWN = 0, 1013 + PERF_BPF_EVENT_PROG_LOAD = 1, 1014 + PERF_BPF_EVENT_PROG_UNLOAD = 2, 1015 + PERF_BPF_EVENT_MAX, /* non-ABI */ 969 1016 }; 970 1017 971 1018 #define PERF_MAX_STACK_DEPTH 127
+1 -1
kernel/bpf/core.c
··· 495 495 *symbol_end = addr + hdr->pages * PAGE_SIZE; 496 496 } 497 497 498 - static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) 498 + void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) 499 499 { 500 500 const char *end = sym + KSYM_NAME_LEN; 501 501 const struct btf_type *type;
+2
kernel/bpf/syscall.c
··· 1211 1211 static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) 1212 1212 { 1213 1213 if (atomic_dec_and_test(&prog->aux->refcnt)) { 1214 + perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0); 1214 1215 /* bpf_prog_free_id() must be called first */ 1215 1216 bpf_prog_free_id(prog, do_idr_lock); 1216 1217 bpf_prog_kallsyms_del_all(prog); ··· 1555 1554 } 1556 1555 1557 1556 bpf_prog_kallsyms_add(prog); 1557 + perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 1558 1558 return err; 1559 1559 1560 1560 free_used_maps:
+219 -5
kernel/events/core.c
··· 385 385 static atomic_t nr_task_events __read_mostly; 386 386 static atomic_t nr_freq_events __read_mostly; 387 387 static atomic_t nr_switch_events __read_mostly; 388 + static atomic_t nr_ksymbol_events __read_mostly; 389 + static atomic_t nr_bpf_events __read_mostly; 388 390 389 391 static LIST_HEAD(pmus); 390 392 static DEFINE_MUTEX(pmus_lock); ··· 4237 4235 4238 4236 if (attr->mmap || attr->mmap_data || attr->mmap2 || 4239 4237 attr->comm || attr->comm_exec || 4240 - attr->task || 4238 + attr->task || attr->ksymbol || 4241 4239 attr->context_switch) 4242 4240 return true; 4243 4241 return false; ··· 4307 4305 dec = true; 4308 4306 if (has_branch_stack(event)) 4309 4307 dec = true; 4308 + if (event->attr.ksymbol) 4309 + atomic_dec(&nr_ksymbol_events); 4310 + if (event->attr.bpf_event) 4311 + atomic_dec(&nr_bpf_events); 4310 4312 4311 4313 if (dec) { 4312 4314 if (!atomic_add_unless(&perf_sched_count, -1, 1)) ··· 6495 6489 data->phys_addr = perf_virt_to_phys(data->addr); 6496 6490 } 6497 6491 6498 - static __always_inline void 6492 + static __always_inline int 6499 6493 __perf_event_output(struct perf_event *event, 6500 6494 struct perf_sample_data *data, 6501 6495 struct pt_regs *regs, ··· 6505 6499 { 6506 6500 struct perf_output_handle handle; 6507 6501 struct perf_event_header header; 6502 + int err; 6508 6503 6509 6504 /* protect the callchain buffers */ 6510 6505 rcu_read_lock(); 6511 6506 6512 6507 perf_prepare_sample(&header, data, event, regs); 6513 6508 6514 - if (output_begin(&handle, event, header.size)) 6509 + err = output_begin(&handle, event, header.size); 6510 + if (err) 6515 6511 goto exit; 6516 6512 6517 6513 perf_output_sample(&handle, &header, data, event); ··· 6522 6514 6523 6515 exit: 6524 6516 rcu_read_unlock(); 6517 + return err; 6525 6518 } 6526 6519 6527 6520 void ··· 6541 6532 __perf_event_output(event, data, regs, perf_output_begin_backward); 6542 6533 } 6543 6534 6544 - void 6535 + int 6545 6536 perf_event_output(struct perf_event *event, 6546 6537 struct perf_sample_data *data, 6547 6538 struct pt_regs *regs) 6548 6539 { 6549 - __perf_event_output(event, data, regs, perf_output_begin); 6540 + return __perf_event_output(event, data, regs, perf_output_begin); 6550 6541 } 6551 6542 6552 6543 /* ··· 7657 7648 perf_output_put(&handle, throttle_event); 7658 7649 perf_event__output_id_sample(event, &handle, &sample); 7659 7650 perf_output_end(&handle); 7651 + } 7652 + 7653 + /* 7654 + * ksymbol register/unregister tracking 7655 + */ 7656 + 7657 + struct perf_ksymbol_event { 7658 + const char *name; 7659 + int name_len; 7660 + struct { 7661 + struct perf_event_header header; 7662 + u64 addr; 7663 + u32 len; 7664 + u16 ksym_type; 7665 + u16 flags; 7666 + } event_id; 7667 + }; 7668 + 7669 + static int perf_event_ksymbol_match(struct perf_event *event) 7670 + { 7671 + return event->attr.ksymbol; 7672 + } 7673 + 7674 + static void perf_event_ksymbol_output(struct perf_event *event, void *data) 7675 + { 7676 + struct perf_ksymbol_event *ksymbol_event = data; 7677 + struct perf_output_handle handle; 7678 + struct perf_sample_data sample; 7679 + int ret; 7680 + 7681 + if (!perf_event_ksymbol_match(event)) 7682 + return; 7683 + 7684 + perf_event_header__init_id(&ksymbol_event->event_id.header, 7685 + &sample, event); 7686 + ret = perf_output_begin(&handle, event, 7687 + ksymbol_event->event_id.header.size); 7688 + if (ret) 7689 + return; 7690 + 7691 + perf_output_put(&handle, ksymbol_event->event_id); 7692 + __output_copy(&handle, ksymbol_event->name, ksymbol_event->name_len); 7693 + perf_event__output_id_sample(event, &handle, &sample); 7694 + 7695 + perf_output_end(&handle); 7696 + } 7697 + 7698 + void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister, 7699 + const char *sym) 7700 + { 7701 + struct perf_ksymbol_event ksymbol_event; 7702 + char name[KSYM_NAME_LEN]; 7703 + u16 flags = 0; 7704 + int name_len; 7705 + 7706 + if (!atomic_read(&nr_ksymbol_events)) 7707 + return; 7708 + 7709 + if (ksym_type >= PERF_RECORD_KSYMBOL_TYPE_MAX || 7710 + ksym_type == PERF_RECORD_KSYMBOL_TYPE_UNKNOWN) 7711 + goto err; 7712 + 7713 + strlcpy(name, sym, KSYM_NAME_LEN); 7714 + name_len = strlen(name) + 1; 7715 + while (!IS_ALIGNED(name_len, sizeof(u64))) 7716 + name[name_len++] = '\0'; 7717 + BUILD_BUG_ON(KSYM_NAME_LEN % sizeof(u64)); 7718 + 7719 + if (unregister) 7720 + flags |= PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER; 7721 + 7722 + ksymbol_event = (struct perf_ksymbol_event){ 7723 + .name = name, 7724 + .name_len = name_len, 7725 + .event_id = { 7726 + .header = { 7727 + .type = PERF_RECORD_KSYMBOL, 7728 + .size = sizeof(ksymbol_event.event_id) + 7729 + name_len, 7730 + }, 7731 + .addr = addr, 7732 + .len = len, 7733 + .ksym_type = ksym_type, 7734 + .flags = flags, 7735 + }, 7736 + }; 7737 + 7738 + perf_iterate_sb(perf_event_ksymbol_output, &ksymbol_event, NULL); 7739 + return; 7740 + err: 7741 + WARN_ONCE(1, "%s: Invalid KSYMBOL type 0x%x\n", __func__, ksym_type); 7742 + } 7743 + 7744 + /* 7745 + * bpf program load/unload tracking 7746 + */ 7747 + 7748 + struct perf_bpf_event { 7749 + struct bpf_prog *prog; 7750 + struct { 7751 + struct perf_event_header header; 7752 + u16 type; 7753 + u16 flags; 7754 + u32 id; 7755 + u8 tag[BPF_TAG_SIZE]; 7756 + } event_id; 7757 + }; 7758 + 7759 + static int perf_event_bpf_match(struct perf_event *event) 7760 + { 7761 + return event->attr.bpf_event; 7762 + } 7763 + 7764 + static void perf_event_bpf_output(struct perf_event *event, void *data) 7765 + { 7766 + struct perf_bpf_event *bpf_event = data; 7767 + struct perf_output_handle handle; 7768 + struct perf_sample_data sample; 7769 + int ret; 7770 + 7771 + if (!perf_event_bpf_match(event)) 7772 + return; 7773 + 7774 + perf_event_header__init_id(&bpf_event->event_id.header, 7775 + &sample, event); 7776 + ret = perf_output_begin(&handle, event, 7777 + bpf_event->event_id.header.size); 7778 + if (ret) 7779 + return; 7780 + 7781 + perf_output_put(&handle, bpf_event->event_id); 7782 + perf_event__output_id_sample(event, &handle, &sample); 7783 + 7784 + perf_output_end(&handle); 7785 + } 7786 + 7787 + static void perf_event_bpf_emit_ksymbols(struct bpf_prog *prog, 7788 + enum perf_bpf_event_type type) 7789 + { 7790 + bool unregister = type == PERF_BPF_EVENT_PROG_UNLOAD; 7791 + char sym[KSYM_NAME_LEN]; 7792 + int i; 7793 + 7794 + if (prog->aux->func_cnt == 0) { 7795 + bpf_get_prog_name(prog, sym); 7796 + perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_BPF, 7797 + (u64)(unsigned long)prog->bpf_func, 7798 + prog->jited_len, unregister, sym); 7799 + } else { 7800 + for (i = 0; i < prog->aux->func_cnt; i++) { 7801 + struct bpf_prog *subprog = prog->aux->func[i]; 7802 + 7803 + bpf_get_prog_name(subprog, sym); 7804 + perf_event_ksymbol( 7805 + PERF_RECORD_KSYMBOL_TYPE_BPF, 7806 + (u64)(unsigned long)subprog->bpf_func, 7807 + subprog->jited_len, unregister, sym); 7808 + } 7809 + } 7810 + } 7811 + 7812 + void perf_event_bpf_event(struct bpf_prog *prog, 7813 + enum perf_bpf_event_type type, 7814 + u16 flags) 7815 + { 7816 + struct perf_bpf_event bpf_event; 7817 + 7818 + if (type <= PERF_BPF_EVENT_UNKNOWN || 7819 + type >= PERF_BPF_EVENT_MAX) 7820 + return; 7821 + 7822 + switch (type) { 7823 + case PERF_BPF_EVENT_PROG_LOAD: 7824 + case PERF_BPF_EVENT_PROG_UNLOAD: 7825 + if (atomic_read(&nr_ksymbol_events)) 7826 + perf_event_bpf_emit_ksymbols(prog, type); 7827 + break; 7828 + default: 7829 + break; 7830 + } 7831 + 7832 + if (!atomic_read(&nr_bpf_events)) 7833 + return; 7834 + 7835 + bpf_event = (struct perf_bpf_event){ 7836 + .prog = prog, 7837 + .event_id = { 7838 + .header = { 7839 + .type = PERF_RECORD_BPF_EVENT, 7840 + .size = sizeof(bpf_event.event_id), 7841 + }, 7842 + .type = type, 7843 + .flags = flags, 7844 + .id = prog->aux->id, 7845 + }, 7846 + }; 7847 + 7848 + BUILD_BUG_ON(BPF_TAG_SIZE % sizeof(u64)); 7849 + 7850 + memcpy(bpf_event.event_id.tag, prog->tag, BPF_TAG_SIZE); 7851 + perf_iterate_sb(perf_event_bpf_output, &bpf_event, NULL); 7660 7852 } 7661 7853 7662 7854 void perf_event_itrace_started(struct perf_event *event) ··· 10119 9909 inc = true; 10120 9910 if (is_cgroup_event(event)) 10121 9911 inc = true; 9912 + if (event->attr.ksymbol) 9913 + atomic_inc(&nr_ksymbol_events); 9914 + if (event->attr.bpf_event) 9915 + atomic_inc(&nr_bpf_events); 10122 9916 10123 9917 if (inc) { 10124 9918 /*
+1 -1
kernel/kallsyms.c
··· 494 494 495 495 static int get_ksymbol_bpf(struct kallsym_iter *iter) 496 496 { 497 - iter->module_name[0] = '\0'; 497 + strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN); 498 498 iter->exported = 0; 499 499 return bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end, 500 500 &iter->value, &iter->type,
+1 -2
kernel/trace/bpf_trace.c
··· 431 431 if (unlikely(event->oncpu != cpu)) 432 432 return -EOPNOTSUPP; 433 433 434 - perf_event_output(event, sd, regs); 435 - return 0; 434 + return perf_event_output(event, sd, regs); 436 435 } 437 436 438 437 BPF_CALL_5(bpf_perf_event_output, struct pt_regs *, regs, struct bpf_map *, map,
+52 -1
tools/include/uapi/linux/perf_event.h
··· 372 372 context_switch : 1, /* context switch data */ 373 373 write_backward : 1, /* Write ring buffer from end to beginning */ 374 374 namespaces : 1, /* include namespaces data */ 375 - __reserved_1 : 35; 375 + ksymbol : 1, /* include ksymbol events */ 376 + bpf_event : 1, /* include bpf events */ 377 + __reserved_1 : 33; 376 378 377 379 union { 378 380 __u32 wakeup_events; /* wakeup every n events */ ··· 965 963 */ 966 964 PERF_RECORD_NAMESPACES = 16, 967 965 966 + /* 967 + * Record ksymbol register/unregister events: 968 + * 969 + * struct { 970 + * struct perf_event_header header; 971 + * u64 addr; 972 + * u32 len; 973 + * u16 ksym_type; 974 + * u16 flags; 975 + * char name[]; 976 + * struct sample_id sample_id; 977 + * }; 978 + */ 979 + PERF_RECORD_KSYMBOL = 17, 980 + 981 + /* 982 + * Record bpf events: 983 + * enum perf_bpf_event_type { 984 + * PERF_BPF_EVENT_UNKNOWN = 0, 985 + * PERF_BPF_EVENT_PROG_LOAD = 1, 986 + * PERF_BPF_EVENT_PROG_UNLOAD = 2, 987 + * }; 988 + * 989 + * struct { 990 + * struct perf_event_header header; 991 + * u16 type; 992 + * u16 flags; 993 + * u32 id; 994 + * u8 tag[BPF_TAG_SIZE]; 995 + * struct sample_id sample_id; 996 + * }; 997 + */ 998 + PERF_RECORD_BPF_EVENT = 18, 999 + 968 1000 PERF_RECORD_MAX, /* non-ABI */ 1001 + }; 1002 + 1003 + enum perf_record_ksymbol_type { 1004 + PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0, 1005 + PERF_RECORD_KSYMBOL_TYPE_BPF = 1, 1006 + PERF_RECORD_KSYMBOL_TYPE_MAX /* non-ABI */ 1007 + }; 1008 + 1009 + #define PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER (1 << 0) 1010 + 1011 + enum perf_bpf_event_type { 1012 + PERF_BPF_EVENT_UNKNOWN = 0, 1013 + PERF_BPF_EVENT_PROG_LOAD = 1, 1014 + PERF_BPF_EVENT_PROG_UNLOAD = 2, 1015 + PERF_BPF_EVENT_MAX, /* non-ABI */ 969 1016 }; 970 1017 971 1018 #define PERF_MAX_STACK_DEPTH 127
+2 -2
tools/perf/builtin-c2c.c
··· 2343 2343 struct c2c_cacheline_browser *cl_browser; 2344 2344 struct hist_browser *browser; 2345 2345 int key = -1; 2346 - const char help[] = 2346 + static const char help[] = 2347 2347 " ENTER Toggle callchains (if present) \n" 2348 2348 " n Toggle Node details info \n" 2349 2349 " s Toggle full length of symbol and source line columns \n" ··· 2424 2424 { 2425 2425 struct hist_browser *browser; 2426 2426 int key = -1; 2427 - const char help[] = 2427 + static const char help[] = 2428 2428 " d Display cacheline details \n" 2429 2429 " ENTER Toggle callchains (if present) \n" 2430 2430 " q Quit \n";
+2 -2
tools/perf/builtin-kmem.c
··· 334 334 struct alloc_func *func; 335 335 struct machine *machine = &kmem_session->machines.host; 336 336 regex_t alloc_func_regex; 337 - const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?"; 337 + static const char pattern[] = "^_?_?(alloc|get_free|get_zeroed)_pages?"; 338 338 339 339 ret = regcomp(&alloc_func_regex, pattern, REG_EXTENDED); 340 340 if (ret) { ··· 1924 1924 NULL 1925 1925 }; 1926 1926 struct perf_session *session; 1927 - const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n"; 1927 + static const char errmsg[] = "No %s allocation events found. Have you run 'perf kmem record --%s'?\n"; 1928 1928 int ret = perf_config(kmem_config, NULL); 1929 1929 1930 1930 if (ret)
+7
tools/perf/builtin-record.c
··· 41 41 #include "util/perf-hooks.h" 42 42 #include "util/time-utils.h" 43 43 #include "util/units.h" 44 + #include "util/bpf-event.h" 44 45 #include "asm/bug.h" 45 46 46 47 #include <errno.h> ··· 1083 1082 return err; 1084 1083 } 1085 1084 1085 + err = perf_event__synthesize_bpf_events(tool, process_synthesized_event, 1086 + machine, opts); 1087 + if (err < 0) 1088 + pr_warning("Couldn't synthesize bpf events.\n"); 1089 + 1086 1090 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 1087 1091 process_synthesized_event, opts->sample_address, 1088 1092 1); ··· 1845 1839 OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize, 1846 1840 "synthesize non-sample events at the end of output"), 1847 1841 OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"), 1842 + OPT_BOOLEAN(0, "bpf-event", &record.opts.bpf_event, "record bpf events"), 1848 1843 OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq, 1849 1844 "Fail if the specified frequency can't be used"), 1850 1845 OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
+3 -3
tools/perf/builtin-report.c
··· 956 956 int branch_mode = -1; 957 957 bool branch_call_mode = false; 958 958 #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" 959 - const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" 960 - CALLCHAIN_REPORT_HELP 961 - "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; 959 + static const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" 960 + CALLCHAIN_REPORT_HELP 961 + "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; 962 962 char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; 963 963 const char * const report_usage[] = { 964 964 "perf report [<options>]",
+1 -1
tools/perf/builtin-sched.c
··· 3336 3336 3337 3337 int cmd_sched(int argc, const char **argv) 3338 3338 { 3339 - const char default_sort_order[] = "avg, max, switch, runtime"; 3339 + static const char default_sort_order[] = "avg, max, switch, runtime"; 3340 3340 struct perf_sched sched = { 3341 3341 .tool = { 3342 3342 .sample = perf_sched__process_tracepoint_sample,
-1
tools/perf/builtin-stat.c
··· 83 83 #include <unistd.h> 84 84 #include <sys/time.h> 85 85 #include <sys/resource.h> 86 - #include <sys/wait.h> 87 86 88 87 #include "sane_ctype.h" 89 88
+7
tools/perf/builtin-top.c
··· 22 22 #include "perf.h" 23 23 24 24 #include "util/annotate.h" 25 + #include "util/bpf-event.h" 25 26 #include "util/config.h" 26 27 #include "util/color.h" 27 28 #include "util/drv_configs.h" ··· 1215 1214 perf_set_multithreaded(); 1216 1215 1217 1216 init_process_thread(top); 1217 + 1218 + ret = perf_event__synthesize_bpf_events(&top->tool, perf_event__process, 1219 + &top->session->machines.host, 1220 + &top->record_opts); 1221 + if (ret < 0) 1222 + pr_warning("Couldn't synthesize bpf events.\n"); 1218 1223 1219 1224 machine__synthesize_threads(&top->session->machines.host, &opts->target, 1220 1225 top->evlist->threads, false,
+2 -2
tools/perf/examples/bpf/augmented_raw_syscalls.c
··· 141 141 len = sizeof(augmented_args.args); 142 142 } 143 143 144 - perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len); 145 - return 0; 144 + /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ 145 + return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len); 146 146 } 147 147 148 148 SEC("raw_syscalls:sys_exit")
+7 -7
tools/perf/examples/bpf/augmented_syscalls.c
··· 55 55 len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size; \ 56 56 len &= sizeof(augmented_args.filename.value) - 1; \ 57 57 } \ 58 - perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 59 - &augmented_args, len); \ 60 - return 0; \ 58 + /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ \ 59 + return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 60 + &augmented_args, len); \ 61 61 } \ 62 62 int syscall_exit(syscall)(struct syscall_exit_args *args) \ 63 63 { \ ··· 125 125 /* addrlen = augmented_args.args.addrlen; */ \ 126 126 /* */ \ 127 127 probe_read(&augmented_args.addr, addrlen, args->addr_ptr); \ 128 - perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 129 - &augmented_args, \ 130 - sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen); \ 131 - return 0; \ 128 + /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ \ 129 + return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 130 + &augmented_args, \ 131 + sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen);\ 132 132 } \ 133 133 int syscall_exit(syscall)(struct syscall_exit_args *args) \ 134 134 { \
+5 -5
tools/perf/examples/bpf/etcsnoop.c
··· 49 49 args->filename_ptr); \ 50 50 if (__builtin_memcmp(augmented_args.filename.value, etc, 4) != 0) \ 51 51 return 0; \ 52 - perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 53 - &augmented_args, \ 54 - (sizeof(augmented_args) - sizeof(augmented_args.filename.value) + \ 55 - augmented_args.filename.size)); \ 56 - return 0; \ 52 + /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */ \ 53 + return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, \ 54 + &augmented_args, \ 55 + (sizeof(augmented_args) - sizeof(augmented_args.filename.value) + \ 56 + augmented_args.filename.size)); \ 57 57 } 58 58 59 59 struct syscall_enter_openat_args {
+1
tools/perf/perf.h
··· 66 66 bool ignore_missing_thread; 67 67 bool strict_freq; 68 68 bool sample_id; 69 + bool bpf_event; 69 70 unsigned int freq; 70 71 unsigned int mmap_pages; 71 72 unsigned int auxtrace_mmap_pages;
-1
tools/perf/tests/bp_account.c
··· 15 15 #include <sys/mman.h> 16 16 #include <linux/compiler.h> 17 17 #include <linux/hw_breakpoint.h> 18 - #include <sys/ioctl.h> 19 18 20 19 #include "tests.h" 21 20 #include "debug.h"
+1 -1
tools/perf/ui/browsers/header.c
··· 35 35 { 36 36 int key; 37 37 unsigned long offset; 38 - const char help[] = 38 + static const char help[] = 39 39 "h/?/F1 Show this window\n" 40 40 "UP/DOWN/PGUP\n" 41 41 "PGDN/SPACE\n"
+2 -2
tools/perf/ui/browsers/hists.c
··· 2748 2748 "S Zoom into current Processor Socket\n" \ 2749 2749 2750 2750 /* help messages are sorted by lexical order of the hotkey */ 2751 - const char report_help[] = HIST_BROWSER_HELP_COMMON 2751 + static const char report_help[] = HIST_BROWSER_HELP_COMMON 2752 2752 "i Show header information\n" 2753 2753 "P Print histograms to perf.hist.N\n" 2754 2754 "r Run available scripts\n" ··· 2756 2756 "t Zoom into current Thread\n" 2757 2757 "V Verbose (DSO names in callchains, etc)\n" 2758 2758 "/ Filter symbol by name"; 2759 - const char top_help[] = HIST_BROWSER_HELP_COMMON 2759 + static const char top_help[] = HIST_BROWSER_HELP_COMMON 2760 2760 "P Print histograms to perf.hist.N\n" 2761 2761 "t Zoom into current Thread\n" 2762 2762 "V Verbose (DSO names in callchains, etc)\n"
+5
tools/perf/util/Build
··· 35 35 libperf-y += symbol.o 36 36 libperf-y += symbol_fprintf.o 37 37 libperf-y += color.o 38 + libperf-y += color_config.o 38 39 libperf-y += metricgroup.o 39 40 libperf-y += header.o 40 41 libperf-y += callchain.o ··· 45 44 libperf-y += map.o 46 45 libperf-y += pstack.o 47 46 libperf-y += session.o 47 + libperf-y += sample-raw.o 48 + libperf-y += s390-sample-raw.o 48 49 libperf-$(CONFIG_TRACE) += syscalltbl.o 49 50 libperf-y += ordered-events.o 50 51 libperf-y += namespaces.o ··· 154 151 endif 155 152 156 153 libperf-y += perf-hooks.o 154 + 155 + libperf-$(CONFIG_LIBBPF) += bpf-event.o 157 156 158 157 libperf-$(CONFIG_CXX) += c++/ 159 158
+257
tools/perf/util/bpf-event.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <errno.h> 3 + #include <stdlib.h> 4 + #include <bpf/bpf.h> 5 + #include <bpf/btf.h> 6 + #include <linux/btf.h> 7 + #include "bpf-event.h" 8 + #include "debug.h" 9 + #include "symbol.h" 10 + 11 + #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) 12 + 13 + static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len) 14 + { 15 + int ret = 0; 16 + size_t i; 17 + 18 + for (i = 0; i < len; i++) 19 + ret += snprintf(buf + ret, size - ret, "%02x", data[i]); 20 + return ret; 21 + } 22 + 23 + int machine__process_bpf_event(struct machine *machine __maybe_unused, 24 + union perf_event *event, 25 + struct perf_sample *sample __maybe_unused) 26 + { 27 + if (dump_trace) 28 + perf_event__fprintf_bpf_event(event, stdout); 29 + return 0; 30 + } 31 + 32 + /* 33 + * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf 34 + * program. One PERF_RECORD_BPF_EVENT is generated for the program. And 35 + * one PERF_RECORD_KSYMBOL is generated for each sub program. 36 + * 37 + * Returns: 38 + * 0 for success; 39 + * -1 for failures; 40 + * -2 for lack of kernel support. 41 + */ 42 + static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool, 43 + perf_event__handler_t process, 44 + struct machine *machine, 45 + int fd, 46 + union perf_event *event, 47 + struct record_opts *opts) 48 + { 49 + struct ksymbol_event *ksymbol_event = &event->ksymbol_event; 50 + struct bpf_event *bpf_event = &event->bpf_event; 51 + u32 sub_prog_cnt, i, func_info_rec_size = 0; 52 + u8 (*prog_tags)[BPF_TAG_SIZE] = NULL; 53 + struct bpf_prog_info info = { .type = 0, }; 54 + u32 info_len = sizeof(info); 55 + void *func_infos = NULL; 56 + u64 *prog_addrs = NULL; 57 + struct btf *btf = NULL; 58 + u32 *prog_lens = NULL; 59 + bool has_btf = false; 60 + char errbuf[512]; 61 + int err = 0; 62 + 63 + /* Call bpf_obj_get_info_by_fd() to get sizes of arrays */ 64 + err = bpf_obj_get_info_by_fd(fd, &info, &info_len); 65 + 66 + if (err) { 67 + pr_debug("%s: failed to get BPF program info: %s, aborting\n", 68 + __func__, str_error_r(errno, errbuf, sizeof(errbuf))); 69 + return -1; 70 + } 71 + if (info_len < offsetof(struct bpf_prog_info, prog_tags)) { 72 + pr_debug("%s: the kernel is too old, aborting\n", __func__); 73 + return -2; 74 + } 75 + 76 + /* number of ksyms, func_lengths, and tags should match */ 77 + sub_prog_cnt = info.nr_jited_ksyms; 78 + if (sub_prog_cnt != info.nr_prog_tags || 79 + sub_prog_cnt != info.nr_jited_func_lens) 80 + return -1; 81 + 82 + /* check BTF func info support */ 83 + if (info.btf_id && info.nr_func_info && info.func_info_rec_size) { 84 + /* btf func info number should be same as sub_prog_cnt */ 85 + if (sub_prog_cnt != info.nr_func_info) { 86 + pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__); 87 + return -1; 88 + } 89 + if (btf__get_from_id(info.btf_id, &btf)) { 90 + pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info.btf_id); 91 + return -1; 92 + } 93 + func_info_rec_size = info.func_info_rec_size; 94 + func_infos = calloc(sub_prog_cnt, func_info_rec_size); 95 + if (!func_infos) { 96 + pr_debug("%s: failed to allocate memory for func_infos, aborting\n", __func__); 97 + return -1; 98 + } 99 + has_btf = true; 100 + } 101 + 102 + /* 103 + * We need address, length, and tag for each sub program. 104 + * Allocate memory and call bpf_obj_get_info_by_fd() again 105 + */ 106 + prog_addrs = calloc(sub_prog_cnt, sizeof(u64)); 107 + if (!prog_addrs) { 108 + pr_debug("%s: failed to allocate memory for prog_addrs, aborting\n", __func__); 109 + goto out; 110 + } 111 + prog_lens = calloc(sub_prog_cnt, sizeof(u32)); 112 + if (!prog_lens) { 113 + pr_debug("%s: failed to allocate memory for prog_lens, aborting\n", __func__); 114 + goto out; 115 + } 116 + prog_tags = calloc(sub_prog_cnt, BPF_TAG_SIZE); 117 + if (!prog_tags) { 118 + pr_debug("%s: failed to allocate memory for prog_tags, aborting\n", __func__); 119 + goto out; 120 + } 121 + 122 + memset(&info, 0, sizeof(info)); 123 + info.nr_jited_ksyms = sub_prog_cnt; 124 + info.nr_jited_func_lens = sub_prog_cnt; 125 + info.nr_prog_tags = sub_prog_cnt; 126 + info.jited_ksyms = ptr_to_u64(prog_addrs); 127 + info.jited_func_lens = ptr_to_u64(prog_lens); 128 + info.prog_tags = ptr_to_u64(prog_tags); 129 + info_len = sizeof(info); 130 + if (has_btf) { 131 + info.nr_func_info = sub_prog_cnt; 132 + info.func_info_rec_size = func_info_rec_size; 133 + info.func_info = ptr_to_u64(func_infos); 134 + } 135 + 136 + err = bpf_obj_get_info_by_fd(fd, &info, &info_len); 137 + if (err) { 138 + pr_debug("%s: failed to get BPF program info, aborting\n", __func__); 139 + goto out; 140 + } 141 + 142 + /* Synthesize PERF_RECORD_KSYMBOL */ 143 + for (i = 0; i < sub_prog_cnt; i++) { 144 + const struct bpf_func_info *finfo; 145 + const char *short_name = NULL; 146 + const struct btf_type *t; 147 + int name_len; 148 + 149 + *ksymbol_event = (struct ksymbol_event){ 150 + .header = { 151 + .type = PERF_RECORD_KSYMBOL, 152 + .size = sizeof(struct ksymbol_event), 153 + }, 154 + .addr = prog_addrs[i], 155 + .len = prog_lens[i], 156 + .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF, 157 + .flags = 0, 158 + }; 159 + name_len = snprintf(ksymbol_event->name, KSYM_NAME_LEN, 160 + "bpf_prog_"); 161 + name_len += snprintf_hex(ksymbol_event->name + name_len, 162 + KSYM_NAME_LEN - name_len, 163 + prog_tags[i], BPF_TAG_SIZE); 164 + if (has_btf) { 165 + finfo = func_infos + i * info.func_info_rec_size; 166 + t = btf__type_by_id(btf, finfo->type_id); 167 + short_name = btf__name_by_offset(btf, t->name_off); 168 + } else if (i == 0 && sub_prog_cnt == 1) { 169 + /* no subprog */ 170 + if (info.name[0]) 171 + short_name = info.name; 172 + } else 173 + short_name = "F"; 174 + if (short_name) 175 + name_len += snprintf(ksymbol_event->name + name_len, 176 + KSYM_NAME_LEN - name_len, 177 + "_%s", short_name); 178 + 179 + ksymbol_event->header.size += PERF_ALIGN(name_len + 1, 180 + sizeof(u64)); 181 + err = perf_tool__process_synth_event(tool, event, 182 + machine, process); 183 + } 184 + 185 + /* Synthesize PERF_RECORD_BPF_EVENT */ 186 + if (opts->bpf_event) { 187 + *bpf_event = (struct bpf_event){ 188 + .header = { 189 + .type = PERF_RECORD_BPF_EVENT, 190 + .size = sizeof(struct bpf_event), 191 + }, 192 + .type = PERF_BPF_EVENT_PROG_LOAD, 193 + .flags = 0, 194 + .id = info.id, 195 + }; 196 + memcpy(bpf_event->tag, prog_tags[i], BPF_TAG_SIZE); 197 + err = perf_tool__process_synth_event(tool, event, 198 + machine, process); 199 + } 200 + 201 + out: 202 + free(prog_tags); 203 + free(prog_lens); 204 + free(prog_addrs); 205 + free(func_infos); 206 + free(btf); 207 + return err ? -1 : 0; 208 + } 209 + 210 + int perf_event__synthesize_bpf_events(struct perf_tool *tool, 211 + perf_event__handler_t process, 212 + struct machine *machine, 213 + struct record_opts *opts) 214 + { 215 + union perf_event *event; 216 + __u32 id = 0; 217 + int err; 218 + int fd; 219 + 220 + event = malloc(sizeof(event->bpf_event) + KSYM_NAME_LEN); 221 + if (!event) 222 + return -1; 223 + while (true) { 224 + err = bpf_prog_get_next_id(id, &id); 225 + if (err) { 226 + if (errno == ENOENT) { 227 + err = 0; 228 + break; 229 + } 230 + pr_debug("%s: can't get next program: %s%s", 231 + __func__, strerror(errno), 232 + errno == EINVAL ? " -- kernel too old?" : ""); 233 + /* don't report error on old kernel */ 234 + err = (errno == EINVAL) ? 0 : -1; 235 + break; 236 + } 237 + fd = bpf_prog_get_fd_by_id(id); 238 + if (fd < 0) { 239 + pr_debug("%s: failed to get fd for prog_id %u\n", 240 + __func__, id); 241 + continue; 242 + } 243 + 244 + err = perf_event__synthesize_one_bpf_prog(tool, process, 245 + machine, fd, 246 + event, opts); 247 + close(fd); 248 + if (err) { 249 + /* do not return error for old kernel */ 250 + if (err == -2) 251 + err = 0; 252 + break; 253 + } 254 + } 255 + free(event); 256 + return err; 257 + }
+38
tools/perf/util/bpf-event.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __PERF_BPF_EVENT_H 3 + #define __PERF_BPF_EVENT_H 4 + 5 + #include <linux/compiler.h> 6 + #include "event.h" 7 + 8 + struct machine; 9 + union perf_event; 10 + struct perf_sample; 11 + struct perf_tool; 12 + struct record_opts; 13 + 14 + #ifdef HAVE_LIBBPF_SUPPORT 15 + int machine__process_bpf_event(struct machine *machine, union perf_event *event, 16 + struct perf_sample *sample); 17 + 18 + int perf_event__synthesize_bpf_events(struct perf_tool *tool, 19 + perf_event__handler_t process, 20 + struct machine *machine, 21 + struct record_opts *opts); 22 + #else 23 + static inline int machine__process_bpf_event(struct machine *machine __maybe_unused, 24 + union perf_event *event __maybe_unused, 25 + struct perf_sample *sample __maybe_unused) 26 + { 27 + return 0; 28 + } 29 + 30 + static inline int perf_event__synthesize_bpf_events(struct perf_tool *tool __maybe_unused, 31 + perf_event__handler_t process __maybe_unused, 32 + struct machine *machine __maybe_unused, 33 + struct record_opts *opts __maybe_unused) 34 + { 35 + return 0; 36 + } 37 + #endif // HAVE_LIBBPF_SUPPORT 38 + #endif
-39
tools/perf/util/color.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include <linux/kernel.h> 3 3 #include "cache.h" 4 - #include "config.h" 5 4 #include <stdlib.h> 6 5 #include <stdio.h> 7 6 #include "color.h" ··· 8 9 #include <unistd.h> 9 10 10 11 int perf_use_color_default = -1; 11 - 12 - int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) 13 - { 14 - if (value) { 15 - if (!strcasecmp(value, "never")) 16 - return 0; 17 - if (!strcasecmp(value, "always")) 18 - return 1; 19 - if (!strcasecmp(value, "auto")) 20 - goto auto_color; 21 - } 22 - 23 - /* Missing or explicit false to turn off colorization */ 24 - if (!perf_config_bool(var, value)) 25 - return 0; 26 - 27 - /* any normal truth value defaults to 'auto' */ 28 - auto_color: 29 - if (stdout_is_tty < 0) 30 - stdout_is_tty = isatty(1); 31 - if (stdout_is_tty || pager_in_use()) { 32 - char *term = getenv("TERM"); 33 - if (term && strcmp(term, "dumb")) 34 - return 1; 35 - } 36 - return 0; 37 - } 38 - 39 - int perf_color_default_config(const char *var, const char *value, 40 - void *cb __maybe_unused) 41 - { 42 - if (!strcmp(var, "color.ui")) { 43 - perf_use_color_default = perf_config_colorbool(var, value, -1); 44 - return 0; 45 - } 46 - 47 - return 0; 48 - } 49 12 50 13 static int __color_vsnprintf(char *bf, size_t size, const char *color, 51 14 const char *fmt, va_list args, const char *trail)
+47
tools/perf/util/color_config.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/kernel.h> 3 + #include "cache.h" 4 + #include "config.h" 5 + #include <stdlib.h> 6 + #include <stdio.h> 7 + #include "color.h" 8 + #include <math.h> 9 + #include <unistd.h> 10 + 11 + int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) 12 + { 13 + if (value) { 14 + if (!strcasecmp(value, "never")) 15 + return 0; 16 + if (!strcasecmp(value, "always")) 17 + return 1; 18 + if (!strcasecmp(value, "auto")) 19 + goto auto_color; 20 + } 21 + 22 + /* Missing or explicit false to turn off colorization */ 23 + if (!perf_config_bool(var, value)) 24 + return 0; 25 + 26 + /* any normal truth value defaults to 'auto' */ 27 + auto_color: 28 + if (stdout_is_tty < 0) 29 + stdout_is_tty = isatty(1); 30 + if (stdout_is_tty || pager_in_use()) { 31 + char *term = getenv("TERM"); 32 + if (term && strcmp(term, "dumb")) 33 + return 1; 34 + } 35 + return 0; 36 + } 37 + 38 + int perf_color_default_config(const char *var, const char *value, 39 + void *cb __maybe_unused) 40 + { 41 + if (!strcmp(var, "color.ui")) { 42 + perf_use_color_default = perf_config_colorbool(var, value, -1); 43 + return 0; 44 + } 45 + 46 + return 0; 47 + }
-1
tools/perf/util/dso.h
··· 8 8 #include <sys/types.h> 9 9 #include <stdbool.h> 10 10 #include "rwsem.h" 11 - #include <linux/types.h> 12 11 #include <linux/bitops.h> 13 12 #include "map.h" 14 13 #include "namespaces.h"
+41
tools/perf/util/event.c
··· 24 24 #include "symbol/kallsyms.h" 25 25 #include "asm/bug.h" 26 26 #include "stat.h" 27 + #include "session.h" 28 + #include "bpf-event.h" 27 29 28 30 #define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 29 31 ··· 47 45 [PERF_RECORD_SWITCH] = "SWITCH", 48 46 [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE", 49 47 [PERF_RECORD_NAMESPACES] = "NAMESPACES", 48 + [PERF_RECORD_KSYMBOL] = "KSYMBOL", 49 + [PERF_RECORD_BPF_EVENT] = "BPF_EVENT", 50 50 [PERF_RECORD_HEADER_ATTR] = "ATTR", 51 51 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 52 52 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", ··· 1333 1329 return machine__process_switch_event(machine, event); 1334 1330 } 1335 1331 1332 + int perf_event__process_ksymbol(struct perf_tool *tool __maybe_unused, 1333 + union perf_event *event, 1334 + struct perf_sample *sample __maybe_unused, 1335 + struct machine *machine) 1336 + { 1337 + return machine__process_ksymbol(machine, event, sample); 1338 + } 1339 + 1340 + int perf_event__process_bpf_event(struct perf_tool *tool __maybe_unused, 1341 + union perf_event *event, 1342 + struct perf_sample *sample __maybe_unused, 1343 + struct machine *machine) 1344 + { 1345 + return machine__process_bpf_event(machine, event, sample); 1346 + } 1347 + 1336 1348 size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 1337 1349 { 1338 1350 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", ··· 1481 1461 return fprintf(fp, " lost %" PRIu64 "\n", event->lost.lost); 1482 1462 } 1483 1463 1464 + size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp) 1465 + { 1466 + return fprintf(fp, " ksymbol event with addr %" PRIx64 " len %u type %u flags 0x%x name %s\n", 1467 + event->ksymbol_event.addr, event->ksymbol_event.len, 1468 + event->ksymbol_event.ksym_type, 1469 + event->ksymbol_event.flags, event->ksymbol_event.name); 1470 + } 1471 + 1472 + size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp) 1473 + { 1474 + return fprintf(fp, " bpf event with type %u, flags %u, id %u\n", 1475 + event->bpf_event.type, event->bpf_event.flags, 1476 + event->bpf_event.id); 1477 + } 1478 + 1484 1479 size_t perf_event__fprintf(union perf_event *event, FILE *fp) 1485 1480 { 1486 1481 size_t ret = fprintf(fp, "PERF_RECORD_%s", ··· 1530 1495 break; 1531 1496 case PERF_RECORD_LOST: 1532 1497 ret += perf_event__fprintf_lost(event, fp); 1498 + break; 1499 + case PERF_RECORD_KSYMBOL: 1500 + ret += perf_event__fprintf_ksymbol(event, fp); 1501 + break; 1502 + case PERF_RECORD_BPF_EVENT: 1503 + ret += perf_event__fprintf_bpf_event(event, fp); 1533 1504 break; 1534 1505 default: 1535 1506 ret += fprintf(fp, "\n");
+36
tools/perf/util/event.h
··· 5 5 #include <limits.h> 6 6 #include <stdio.h> 7 7 #include <linux/kernel.h> 8 + #include <linux/bpf.h> 8 9 9 10 #include "../perf.h" 10 11 #include "build-id.h" ··· 83 82 u64 time; 84 83 u64 id; 85 84 u64 stream_id; 85 + }; 86 + 87 + #ifndef KSYM_NAME_LEN 88 + #define KSYM_NAME_LEN 256 89 + #endif 90 + 91 + struct ksymbol_event { 92 + struct perf_event_header header; 93 + u64 addr; 94 + u32 len; 95 + u16 ksym_type; 96 + u16 flags; 97 + char name[KSYM_NAME_LEN]; 98 + }; 99 + 100 + struct bpf_event { 101 + struct perf_event_header header; 102 + u16 type; 103 + u16 flags; 104 + u32 id; 105 + 106 + /* for bpf_prog types */ 107 + u8 tag[BPF_TAG_SIZE]; // prog tag 86 108 }; 87 109 88 110 #define PERF_SAMPLE_MASK \ ··· 675 651 struct stat_round_event stat_round; 676 652 struct time_conv_event time_conv; 677 653 struct feature_event feat; 654 + struct ksymbol_event ksymbol_event; 655 + struct bpf_event bpf_event; 678 656 }; 679 657 680 658 void perf_event__print_totals(void); ··· 774 748 union perf_event *event, 775 749 struct perf_sample *sample, 776 750 struct machine *machine); 751 + int perf_event__process_ksymbol(struct perf_tool *tool, 752 + union perf_event *event, 753 + struct perf_sample *sample, 754 + struct machine *machine); 755 + int perf_event__process_bpf_event(struct perf_tool *tool, 756 + union perf_event *event, 757 + struct perf_sample *sample, 758 + struct machine *machine); 777 759 int perf_tool__process_synth_event(struct perf_tool *tool, 778 760 union perf_event *event, 779 761 struct machine *machine, ··· 845 811 size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); 846 812 size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); 847 813 size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp); 814 + size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp); 815 + size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp); 848 816 size_t perf_event__fprintf(union perf_event *event, FILE *fp); 849 817 850 818 int kallsyms__get_function_start(const char *kallsyms_filename,
+3 -1
tools/perf/util/evlist.h
··· 49 49 struct perf_evsel *selected; 50 50 struct events_stats stats; 51 51 struct perf_env *env; 52 + void (*trace_event_sample_raw)(struct perf_evlist *evlist, 53 + union perf_event *event, 54 + struct perf_sample *sample); 52 55 u64 first_sample_time; 53 56 u64 last_sample_time; 54 57 }; ··· 317 314 318 315 struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist, 319 316 struct perf_evsel *evsel); 320 - 321 317 #endif /* __PERF_EVLIST_H */
+18 -1
tools/perf/util/evsel.c
··· 1035 1035 attr->mmap = track; 1036 1036 attr->mmap2 = track && !perf_missing_features.mmap2; 1037 1037 attr->comm = track; 1038 + attr->ksymbol = track && !perf_missing_features.ksymbol; 1039 + attr->bpf_event = track && opts->bpf_event && 1040 + !perf_missing_features.bpf_event; 1038 1041 1039 1042 if (opts->record_namespaces) 1040 1043 attr->namespaces = track; ··· 1655 1652 PRINT_ATTRf(context_switch, p_unsigned); 1656 1653 PRINT_ATTRf(write_backward, p_unsigned); 1657 1654 PRINT_ATTRf(namespaces, p_unsigned); 1655 + PRINT_ATTRf(ksymbol, p_unsigned); 1656 + PRINT_ATTRf(bpf_event, p_unsigned); 1658 1657 1659 1658 PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); 1660 1659 PRINT_ATTRf(bp_type, p_unsigned); ··· 1816 1811 PERF_SAMPLE_BRANCH_NO_CYCLES); 1817 1812 if (perf_missing_features.group_read && evsel->attr.inherit) 1818 1813 evsel->attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); 1814 + if (perf_missing_features.ksymbol) 1815 + evsel->attr.ksymbol = 0; 1816 + if (perf_missing_features.bpf_event) 1817 + evsel->attr.bpf_event = 0; 1819 1818 retry_sample_id: 1820 1819 if (perf_missing_features.sample_id_all) 1821 1820 evsel->attr.sample_id_all = 0; ··· 1939 1930 * Must probe features in the order they were added to the 1940 1931 * perf_event_attr interface. 1941 1932 */ 1942 - if (!perf_missing_features.write_backward && evsel->attr.write_backward) { 1933 + if (!perf_missing_features.bpf_event && evsel->attr.bpf_event) { 1934 + perf_missing_features.bpf_event = true; 1935 + pr_debug2("switching off bpf_event\n"); 1936 + goto fallback_missing_features; 1937 + } else if (!perf_missing_features.ksymbol && evsel->attr.ksymbol) { 1938 + perf_missing_features.ksymbol = true; 1939 + pr_debug2("switching off ksymbol\n"); 1940 + goto fallback_missing_features; 1941 + } else if (!perf_missing_features.write_backward && evsel->attr.write_backward) { 1943 1942 perf_missing_features.write_backward = true; 1944 1943 pr_debug2("switching off write_backward\n"); 1945 1944 goto out_close;
+2
tools/perf/util/evsel.h
··· 168 168 bool lbr_flags; 169 169 bool write_backward; 170 170 bool group_read; 171 + bool ksymbol; 172 + bool bpf_event; 171 173 }; 172 174 173 175 extern struct perf_missing_features perf_missing_features;
+58
tools/perf/util/machine.c
··· 21 21 #include "unwind.h" 22 22 #include "linux/hash.h" 23 23 #include "asm/bug.h" 24 + #include "bpf-event.h" 24 25 25 26 #include "sane_ctype.h" 26 27 #include <symbol/kallsyms.h> ··· 680 679 if (dump_trace) 681 680 perf_event__fprintf_switch(event, stdout); 682 681 return 0; 682 + } 683 + 684 + static int machine__process_ksymbol_register(struct machine *machine, 685 + union perf_event *event, 686 + struct perf_sample *sample __maybe_unused) 687 + { 688 + struct symbol *sym; 689 + struct map *map; 690 + 691 + map = map_groups__find(&machine->kmaps, event->ksymbol_event.addr); 692 + if (!map) { 693 + map = dso__new_map(event->ksymbol_event.name); 694 + if (!map) 695 + return -ENOMEM; 696 + 697 + map->start = event->ksymbol_event.addr; 698 + map->pgoff = map->start; 699 + map->end = map->start + event->ksymbol_event.len; 700 + map_groups__insert(&machine->kmaps, map); 701 + } 702 + 703 + sym = symbol__new(event->ksymbol_event.addr, event->ksymbol_event.len, 704 + 0, 0, event->ksymbol_event.name); 705 + if (!sym) 706 + return -ENOMEM; 707 + dso__insert_symbol(map->dso, sym); 708 + return 0; 709 + } 710 + 711 + static int machine__process_ksymbol_unregister(struct machine *machine, 712 + union perf_event *event, 713 + struct perf_sample *sample __maybe_unused) 714 + { 715 + struct map *map; 716 + 717 + map = map_groups__find(&machine->kmaps, event->ksymbol_event.addr); 718 + if (map) 719 + map_groups__remove(&machine->kmaps, map); 720 + 721 + return 0; 722 + } 723 + 724 + int machine__process_ksymbol(struct machine *machine __maybe_unused, 725 + union perf_event *event, 726 + struct perf_sample *sample) 727 + { 728 + if (dump_trace) 729 + perf_event__fprintf_ksymbol(event, stdout); 730 + 731 + if (event->ksymbol_event.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) 732 + return machine__process_ksymbol_unregister(machine, event, 733 + sample); 734 + return machine__process_ksymbol_register(machine, event, sample); 683 735 } 684 736 685 737 static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename) ··· 1866 1812 case PERF_RECORD_SWITCH: 1867 1813 case PERF_RECORD_SWITCH_CPU_WIDE: 1868 1814 ret = machine__process_switch_event(machine, event); break; 1815 + case PERF_RECORD_KSYMBOL: 1816 + ret = machine__process_ksymbol(machine, event, sample); break; 1817 + case PERF_RECORD_BPF_EVENT: 1818 + ret = machine__process_bpf_event(machine, event, sample); break; 1869 1819 default: 1870 1820 ret = -1; 1871 1821 break;
+3
tools/perf/util/machine.h
··· 130 130 struct perf_sample *sample); 131 131 int machine__process_mmap2_event(struct machine *machine, union perf_event *event, 132 132 struct perf_sample *sample); 133 + int machine__process_ksymbol(struct machine *machine, 134 + union perf_event *event, 135 + struct perf_sample *sample); 133 136 int machine__process_event(struct machine *machine, union perf_event *event, 134 137 struct perf_sample *sample); 135 138
+62
tools/perf/util/s390-cpumcf-kernel.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Support for s390 CPU measurement counter set diagnostic facility 4 + * 5 + * Copyright IBM Corp. 2019 6 + Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> 7 + * Thomas Richter <tmricht@linux.ibm.com> 8 + */ 9 + #ifndef S390_CPUMCF_KERNEL_H 10 + #define S390_CPUMCF_KERNEL_H 11 + 12 + #define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */ 13 + #define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */ 14 + 15 + struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */ 16 + unsigned int def:16; /* 0-15 Data Entry Format */ 17 + unsigned int set:16; /* 16-23 Counter set identifier */ 18 + unsigned int ctr:16; /* 24-39 Number of stored counters */ 19 + unsigned int res1:16; /* 40-63 Reserved */ 20 + }; 21 + 22 + struct cf_trailer_entry { /* CPU-M CF trailer for raw traces (64 byte) */ 23 + /* 0 - 7 */ 24 + union { 25 + struct { 26 + unsigned int clock_base:1; /* TOD clock base */ 27 + unsigned int speed:1; /* CPU speed */ 28 + /* Measurement alerts */ 29 + unsigned int mtda:1; /* Loss of MT ctr. data alert */ 30 + unsigned int caca:1; /* Counter auth. change alert */ 31 + unsigned int lcda:1; /* Loss of counter data alert */ 32 + }; 33 + unsigned long flags; /* 0-63 All indicators */ 34 + }; 35 + /* 8 - 15 */ 36 + unsigned int cfvn:16; /* 64-79 Ctr First Version */ 37 + unsigned int csvn:16; /* 80-95 Ctr Second Version */ 38 + unsigned int cpu_speed:32; /* 96-127 CPU speed */ 39 + /* 16 - 23 */ 40 + unsigned long timestamp; /* 128-191 Timestamp (TOD) */ 41 + /* 24 - 55 */ 42 + union { 43 + struct { 44 + unsigned long progusage1; 45 + unsigned long progusage2; 46 + unsigned long progusage3; 47 + unsigned long tod_base; 48 + }; 49 + unsigned long progusage[4]; 50 + }; 51 + /* 56 - 63 */ 52 + unsigned int mach_type:16; /* Machine type */ 53 + unsigned int res1:16; /* Reserved */ 54 + unsigned int res2:32; /* Reserved */ 55 + }; 56 + 57 + #define CPUMF_CTR_SET_BASIC 0 /* Basic Counter Set */ 58 + #define CPUMF_CTR_SET_USER 1 /* Problem-State Counter Set */ 59 + #define CPUMF_CTR_SET_CRYPTO 2 /* Crypto-Activity Counter Set */ 60 + #define CPUMF_CTR_SET_EXT 3 /* Extended Counter Set */ 61 + #define CPUMF_CTR_SET_MT_DIAG 4 /* MT-diagnostic Counter Set */ 62 + #endif
+73 -4
tools/perf/util/s390-cpumsf.c
··· 162 162 #include "auxtrace.h" 163 163 #include "s390-cpumsf.h" 164 164 #include "s390-cpumsf-kernel.h" 165 + #include "s390-cpumcf-kernel.h" 165 166 #include "config.h" 166 167 167 168 struct s390_cpumsf { ··· 185 184 struct auxtrace_buffer *buffer; 186 185 int cpu; 187 186 FILE *logfile; 187 + FILE *logfile_ctr; 188 188 }; 189 + 190 + /* Check if the raw data should be dumped to file. If this is the case and 191 + * the file to dump to has not been opened for writing, do so. 192 + * 193 + * Return 0 on success and greater zero on error so processing continues. 194 + */ 195 + static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf, 196 + struct perf_sample *sample) 197 + { 198 + struct s390_cpumsf_queue *sfq; 199 + struct auxtrace_queue *q; 200 + int rc = 0; 201 + 202 + if (!sf->use_logfile || sf->queues.nr_queues <= sample->cpu) 203 + return rc; 204 + 205 + q = &sf->queues.queue_array[sample->cpu]; 206 + sfq = q->priv; 207 + if (!sfq) /* Queue not yet allocated */ 208 + return rc; 209 + 210 + if (!sfq->logfile_ctr) { 211 + char *name; 212 + 213 + rc = (sf->logdir) 214 + ? asprintf(&name, "%s/aux.ctr.%02x", 215 + sf->logdir, sample->cpu) 216 + : asprintf(&name, "aux.ctr.%02x", sample->cpu); 217 + if (rc > 0) 218 + sfq->logfile_ctr = fopen(name, "w"); 219 + if (sfq->logfile_ctr == NULL) { 220 + pr_err("Failed to open counter set log file %s, " 221 + "continue...\n", name); 222 + rc = 1; 223 + } 224 + free(name); 225 + } 226 + 227 + if (sfq->logfile_ctr) { 228 + /* See comment above for -4 */ 229 + size_t n = fwrite(sample->raw_data, sample->raw_size - 4, 1, 230 + sfq->logfile_ctr); 231 + if (n != 1) { 232 + pr_err("Failed to write counter set data\n"); 233 + rc = 1; 234 + } 235 + } 236 + return rc; 237 + } 189 238 190 239 /* Display s390 CPU measurement facility basic-sampling data entry */ 191 240 static bool s390_cpumsf_basic_show(const char *color, size_t pos, ··· 843 792 } 844 793 845 794 static int 846 - s390_cpumsf_process_event(struct perf_session *session __maybe_unused, 795 + s390_cpumsf_process_event(struct perf_session *session, 847 796 union perf_event *event, 848 797 struct perf_sample *sample, 849 798 struct perf_tool *tool) ··· 852 801 struct s390_cpumsf, 853 802 auxtrace); 854 803 u64 timestamp = sample->time; 804 + struct perf_evsel *ev_bc000; 805 + 855 806 int err = 0; 856 807 857 808 if (dump_trace) ··· 862 809 if (!tool->ordered_events) { 863 810 pr_err("s390 Auxiliary Trace requires ordered events\n"); 864 811 return -EINVAL; 812 + } 813 + 814 + if (event->header.type == PERF_RECORD_SAMPLE && 815 + sample->raw_size) { 816 + /* Handle event with raw data */ 817 + ev_bc000 = perf_evlist__event2evsel(session->evlist, event); 818 + if (ev_bc000 && 819 + ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG) 820 + err = s390_cpumcf_dumpctr(sf, sample); 821 + return err; 865 822 } 866 823 867 824 if (event->header.type == PERF_RECORD_AUX && ··· 954 891 struct s390_cpumsf_queue *sfq = (struct s390_cpumsf_queue *) 955 892 queues->queue_array[i].priv; 956 893 957 - if (sfq != NULL && sfq->logfile) { 958 - fclose(sfq->logfile); 959 - sfq->logfile = NULL; 894 + if (sfq != NULL) { 895 + if (sfq->logfile) { 896 + fclose(sfq->logfile); 897 + sfq->logfile = NULL; 898 + } 899 + if (sfq->logfile_ctr) { 900 + fclose(sfq->logfile_ctr); 901 + sfq->logfile_ctr = NULL; 902 + } 960 903 } 961 904 zfree(&queues->queue_array[i].priv); 962 905 }
+222
tools/perf/util/s390-sample-raw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright IBM Corp. 2019 4 + * Author(s): Thomas Richter <tmricht@linux.ibm.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License (version 2 only) 8 + * as published by the Free Software Foundation. 9 + * 10 + * Architecture specific trace_event function. Save event's bc000 raw data 11 + * to file. File name is aux.ctr.## where ## stands for the CPU number the 12 + * sample was taken from. 13 + */ 14 + 15 + #include <unistd.h> 16 + #include <stdio.h> 17 + #include <string.h> 18 + #include <inttypes.h> 19 + 20 + #include <sys/stat.h> 21 + #include <linux/compiler.h> 22 + #include <asm/byteorder.h> 23 + 24 + #include "debug.h" 25 + #include "util.h" 26 + #include "auxtrace.h" 27 + #include "session.h" 28 + #include "evlist.h" 29 + #include "config.h" 30 + #include "color.h" 31 + #include "sample-raw.h" 32 + #include "s390-cpumcf-kernel.h" 33 + #include "pmu-events/pmu-events.h" 34 + 35 + static size_t ctrset_size(struct cf_ctrset_entry *set) 36 + { 37 + return sizeof(*set) + set->ctr * sizeof(u64); 38 + } 39 + 40 + static bool ctrset_valid(struct cf_ctrset_entry *set) 41 + { 42 + return set->def == S390_CPUMCF_DIAG_DEF; 43 + } 44 + 45 + /* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte 46 + * aligned and might have trailing padding bytes. 47 + * Display the raw data on screen. 48 + */ 49 + static bool s390_cpumcfdg_testctr(struct perf_sample *sample) 50 + { 51 + size_t len = sample->raw_size, offset = 0; 52 + unsigned char *buf = sample->raw_data; 53 + struct cf_trailer_entry *te; 54 + struct cf_ctrset_entry *cep, ce; 55 + 56 + if (!len) 57 + return false; 58 + while (offset < len) { 59 + cep = (struct cf_ctrset_entry *)(buf + offset); 60 + ce.def = be16_to_cpu(cep->def); 61 + ce.set = be16_to_cpu(cep->set); 62 + ce.ctr = be16_to_cpu(cep->ctr); 63 + ce.res1 = be16_to_cpu(cep->res1); 64 + 65 + if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) { 66 + /* Raw data for counter sets are always multiple of 8 67 + * bytes. Prepending a 4 bytes size field to the 68 + * raw data block in the sample causes the perf tool 69 + * to append 4 padding bytes to make the raw data part 70 + * of the sample a multiple of eight bytes again. 71 + * 72 + * If the last entry (trailer) is 4 bytes off the raw 73 + * area data end, all is good. 74 + */ 75 + if (len - offset - sizeof(*te) == 4) 76 + break; 77 + pr_err("Invalid counter set entry at %zd\n", offset); 78 + return false; 79 + } 80 + offset += ctrset_size(&ce); 81 + } 82 + return true; 83 + } 84 + 85 + /* Dump event bc000 on screen, already tested on correctness. */ 86 + static void s390_cpumcfdg_dumptrail(const char *color, size_t offset, 87 + struct cf_trailer_entry *tep) 88 + { 89 + struct cf_trailer_entry te; 90 + 91 + te.flags = be64_to_cpu(tep->flags); 92 + te.cfvn = be16_to_cpu(tep->cfvn); 93 + te.csvn = be16_to_cpu(tep->csvn); 94 + te.cpu_speed = be32_to_cpu(tep->cpu_speed); 95 + te.timestamp = be64_to_cpu(tep->timestamp); 96 + te.progusage1 = be64_to_cpu(tep->progusage1); 97 + te.progusage2 = be64_to_cpu(tep->progusage2); 98 + te.progusage3 = be64_to_cpu(tep->progusage3); 99 + te.tod_base = be64_to_cpu(tep->tod_base); 100 + te.mach_type = be16_to_cpu(tep->mach_type); 101 + te.res1 = be16_to_cpu(tep->res1); 102 + te.res2 = be32_to_cpu(tep->res2); 103 + 104 + color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c" 105 + " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n", 106 + offset, te.clock_base ? 'T' : ' ', 107 + te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ', 108 + te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ', 109 + te.cfvn, te.csvn, te.cpu_speed, te.timestamp); 110 + color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx" 111 + " Type:%x\n\n", 112 + te.progusage1, te.progusage2, te.progusage3, 113 + te.tod_base, te.mach_type); 114 + } 115 + 116 + /* Return starting number of a counter set */ 117 + static int get_counterset_start(int setnr) 118 + { 119 + switch (setnr) { 120 + case CPUMF_CTR_SET_BASIC: /* Basic counter set */ 121 + return 0; 122 + case CPUMF_CTR_SET_USER: /* Problem state counter set */ 123 + return 32; 124 + case CPUMF_CTR_SET_CRYPTO: /* Crypto counter set */ 125 + return 64; 126 + case CPUMF_CTR_SET_EXT: /* Extended counter set */ 127 + return 128; 128 + case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */ 129 + return 448; 130 + default: 131 + return -1; 132 + } 133 + } 134 + 135 + /* Scan the PMU table and extract the logical name of a counter from the 136 + * PMU events table. Input is the counter set and counter number with in the 137 + * set. Construct the event number and use this as key. If they match return 138 + * the name of this counter. 139 + * If no match is found a NULL pointer is returned. 140 + */ 141 + static const char *get_counter_name(int set, int nr, struct pmu_events_map *map) 142 + { 143 + int rc, event_nr, wanted = get_counterset_start(set) + nr; 144 + 145 + if (map) { 146 + struct pmu_event *evp = map->table; 147 + 148 + for (; evp->name || evp->event || evp->desc; ++evp) { 149 + if (evp->name == NULL || evp->event == NULL) 150 + continue; 151 + rc = sscanf(evp->event, "event=%x", &event_nr); 152 + if (rc == 1 && event_nr == wanted) 153 + return evp->name; 154 + } 155 + } 156 + return NULL; 157 + } 158 + 159 + static void s390_cpumcfdg_dump(struct perf_sample *sample) 160 + { 161 + size_t i, len = sample->raw_size, offset = 0; 162 + unsigned char *buf = sample->raw_data; 163 + const char *color = PERF_COLOR_BLUE; 164 + struct cf_ctrset_entry *cep, ce; 165 + struct pmu_events_map *map; 166 + struct perf_pmu pmu; 167 + u64 *p; 168 + 169 + memset(&pmu, 0, sizeof(pmu)); 170 + map = perf_pmu__find_map(&pmu); 171 + while (offset < len) { 172 + cep = (struct cf_ctrset_entry *)(buf + offset); 173 + 174 + ce.def = be16_to_cpu(cep->def); 175 + ce.set = be16_to_cpu(cep->set); 176 + ce.ctr = be16_to_cpu(cep->ctr); 177 + ce.res1 = be16_to_cpu(cep->res1); 178 + 179 + if (!ctrset_valid(&ce)) { /* Print trailer */ 180 + s390_cpumcfdg_dumptrail(color, offset, 181 + (struct cf_trailer_entry *)cep); 182 + return; 183 + } 184 + 185 + color_fprintf(stdout, color, " [%#08zx] Counterset:%d" 186 + " Counters:%d\n", offset, ce.set, ce.ctr); 187 + for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) { 188 + const char *ev_name = get_counter_name(ce.set, i, map); 189 + 190 + color_fprintf(stdout, color, 191 + "\tCounter:%03d %s Value:%#018lx\n", i, 192 + ev_name ?: "<unknown>", be64_to_cpu(*p)); 193 + } 194 + offset += ctrset_size(&ce); 195 + } 196 + } 197 + 198 + /* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events 199 + * and if the event was triggered by a counter set diagnostic event display 200 + * its raw data. 201 + * The function is only invoked when the dump flag -D is set. 202 + */ 203 + void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event, 204 + struct perf_sample *sample) 205 + { 206 + struct perf_evsel *ev_bc000; 207 + 208 + if (event->header.type != PERF_RECORD_SAMPLE) 209 + return; 210 + 211 + ev_bc000 = perf_evlist__event2evsel(evlist, event); 212 + if (ev_bc000 == NULL || 213 + ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG) 214 + return; 215 + 216 + /* Display raw data on screen */ 217 + if (!s390_cpumcfdg_testctr(sample)) { 218 + pr_err("Invalid counter set data encountered\n"); 219 + return; 220 + } 221 + s390_cpumcfdg_dump(sample); 222 + }
+18
tools/perf/util/sample-raw.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #include <string.h> 4 + #include "evlist.h" 5 + #include "env.h" 6 + #include "sample-raw.h" 7 + 8 + /* 9 + * Check platform the perf data file was created on and perform platform 10 + * specific interpretation. 11 + */ 12 + void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist) 13 + { 14 + const char *arch_pf = perf_env__arch(evlist->env); 15 + 16 + if (arch_pf && !strcmp("s390", arch_pf)) 17 + evlist->trace_event_sample_raw = perf_evlist__s390_sample_raw; 18 + }
+14
tools/perf/util/sample-raw.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __SAMPLE_RAW_H 3 + #define __SAMPLE_RAW_H 1 4 + 5 + struct perf_evlist; 6 + union perf_event; 7 + struct perf_sample; 8 + 9 + void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, 10 + union perf_event *event, 11 + struct perf_sample *sample); 12 + 13 + void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist); 14 + #endif /* __PERF_EVLIST_H */
+63 -35
tools/perf/util/session.c
··· 23 23 #include "auxtrace.h" 24 24 #include "thread.h" 25 25 #include "thread-stack.h" 26 + #include "sample-raw.h" 26 27 #include "stat.h" 27 28 #include "arch/common.h" 28 29 ··· 148 147 perf_session__set_id_hdr_size(session); 149 148 perf_session__set_comm_exec(session); 150 149 } 150 + 151 + perf_evlist__init_trace_event_sample_raw(session->evlist); 151 152 } 152 153 } else { 153 154 session->machines.host.env = &perf_env; ··· 379 376 tool->itrace_start = perf_event__process_itrace_start; 380 377 if (tool->context_switch == NULL) 381 378 tool->context_switch = perf_event__process_switch; 379 + if (tool->ksymbol == NULL) 380 + tool->ksymbol = perf_event__process_ksymbol; 381 + if (tool->bpf_event == NULL) 382 + tool->bpf_event = perf_event__process_bpf_event; 382 383 if (tool->read == NULL) 383 384 tool->read = process_event_sample_stub; 384 385 if (tool->throttle == NULL) ··· 1072 1065 file_offset, event->header.size, event->header.type); 1073 1066 1074 1067 trace_event(event); 1068 + if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw) 1069 + evlist->trace_event_sample_raw(evlist, event, sample); 1075 1070 1076 1071 if (sample) 1077 1072 perf_evlist__print_tstamp(evlist, event, sample); ··· 1314 1305 case PERF_RECORD_SWITCH: 1315 1306 case PERF_RECORD_SWITCH_CPU_WIDE: 1316 1307 return tool->context_switch(tool, event, sample, machine); 1308 + case PERF_RECORD_KSYMBOL: 1309 + return tool->ksymbol(tool, event, sample, machine); 1310 + case PERF_RECORD_BPF_EVENT: 1311 + return tool->bpf_event(tool, event, sample, machine); 1317 1312 default: 1318 1313 ++evlist->stats.nr_unknown_events; 1319 1314 return -1; ··· 1833 1820 #define NUM_MMAPS 128 1834 1821 #endif 1835 1822 1836 - static int __perf_session__process_events(struct perf_session *session, 1837 - u64 data_offset, u64 data_size, 1838 - u64 file_size) 1823 + struct reader { 1824 + int fd; 1825 + u64 data_size; 1826 + u64 data_offset; 1827 + }; 1828 + 1829 + static int 1830 + reader__process_events(struct reader *rd, struct perf_session *session, 1831 + struct ui_progress *prog) 1839 1832 { 1840 - struct ordered_events *oe = &session->ordered_events; 1841 - struct perf_tool *tool = session->tool; 1842 - int fd = perf_data__fd(session->data); 1833 + u64 data_size = rd->data_size; 1843 1834 u64 head, page_offset, file_offset, file_pos, size; 1844 - int err, mmap_prot, mmap_flags, map_idx = 0; 1835 + int err = 0, mmap_prot, mmap_flags, map_idx = 0; 1845 1836 size_t mmap_size; 1846 1837 char *buf, *mmaps[NUM_MMAPS]; 1847 1838 union perf_event *event; 1848 - struct ui_progress prog; 1849 1839 s64 skip; 1850 1840 1851 - perf_tool__fill_defaults(tool); 1852 - 1853 - page_offset = page_size * (data_offset / page_size); 1841 + page_offset = page_size * (rd->data_offset / page_size); 1854 1842 file_offset = page_offset; 1855 - head = data_offset - page_offset; 1843 + head = rd->data_offset - page_offset; 1856 1844 1857 - if (data_size == 0) 1858 - goto out; 1845 + ui_progress__init_size(prog, data_size, "Processing events..."); 1859 1846 1860 - if (data_offset + data_size < file_size) 1861 - file_size = data_offset + data_size; 1862 - 1863 - ui_progress__init_size(&prog, file_size, "Processing events..."); 1847 + data_size += rd->data_offset; 1864 1848 1865 1849 mmap_size = MMAP_SIZE; 1866 - if (mmap_size > file_size) { 1867 - mmap_size = file_size; 1850 + if (mmap_size > data_size) { 1851 + mmap_size = data_size; 1868 1852 session->one_mmap = true; 1869 1853 } 1870 1854 ··· 1875 1865 mmap_flags = MAP_PRIVATE; 1876 1866 } 1877 1867 remap: 1878 - buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd, 1868 + buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, rd->fd, 1879 1869 file_offset); 1880 1870 if (buf == MAP_FAILED) { 1881 1871 pr_err("failed to mmap file\n"); 1882 1872 err = -errno; 1883 - goto out_err; 1873 + goto out; 1884 1874 } 1885 1875 mmaps[map_idx] = buf; 1886 1876 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); ··· 1912 1902 file_offset + head, event->header.size, 1913 1903 event->header.type); 1914 1904 err = -EINVAL; 1915 - goto out_err; 1905 + goto out; 1916 1906 } 1917 1907 1918 1908 if (skip) ··· 1921 1911 head += size; 1922 1912 file_pos += size; 1923 1913 1924 - ui_progress__update(&prog, size); 1914 + ui_progress__update(prog, size); 1925 1915 1926 1916 if (session_done()) 1927 1917 goto out; 1928 1918 1929 - if (file_pos < file_size) 1919 + if (file_pos < data_size) 1930 1920 goto more; 1931 1921 1932 1922 out: 1923 + return err; 1924 + } 1925 + 1926 + static int __perf_session__process_events(struct perf_session *session) 1927 + { 1928 + struct reader rd = { 1929 + .fd = perf_data__fd(session->data), 1930 + .data_size = session->header.data_size, 1931 + .data_offset = session->header.data_offset, 1932 + }; 1933 + struct ordered_events *oe = &session->ordered_events; 1934 + struct perf_tool *tool = session->tool; 1935 + struct ui_progress prog; 1936 + int err; 1937 + 1938 + perf_tool__fill_defaults(tool); 1939 + 1940 + if (rd.data_size == 0) 1941 + return -1; 1942 + 1943 + ui_progress__init_size(&prog, rd.data_size, "Processing events..."); 1944 + 1945 + err = reader__process_events(&rd, session, &prog); 1946 + if (err) 1947 + goto out_err; 1933 1948 /* do the final flush for ordered samples */ 1934 1949 err = ordered_events__flush(oe, OE_FLUSH__FINAL); 1935 1950 if (err) ··· 1979 1944 1980 1945 int perf_session__process_events(struct perf_session *session) 1981 1946 { 1982 - u64 size = perf_data__size(session->data); 1983 - int err; 1984 - 1985 1947 if (perf_session__register_idle_thread(session) < 0) 1986 1948 return -ENOMEM; 1987 1949 1988 - if (!perf_data__is_pipe(session->data)) 1989 - err = __perf_session__process_events(session, 1990 - session->header.data_offset, 1991 - session->header.data_size, size); 1992 - else 1993 - err = __perf_session__process_pipe_events(session); 1950 + if (perf_data__is_pipe(session->data)) 1951 + return __perf_session__process_pipe_events(session); 1994 1952 1995 - return err; 1953 + return __perf_session__process_events(session); 1996 1954 } 1997 1955 1998 1956 bool perf_session__has_traces(struct perf_session *session, const char *msg)
+2
tools/perf/util/setup.py
··· 17 17 vars[var] = sub("-mcet", "", vars[var]) 18 18 if not clang_has_option("-fcf-protection"): 19 19 vars[var] = sub("-fcf-protection", "", vars[var]) 20 + if not clang_has_option("-fstack-clash-protection"): 21 + vars[var] = sub("-fstack-clash-protection", "", vars[var]) 20 22 21 23 from distutils.core import setup, Extension 22 24
+4 -1
tools/perf/util/tool.h
··· 53 53 itrace_start, 54 54 context_switch, 55 55 throttle, 56 - unthrottle; 56 + unthrottle, 57 + ksymbol, 58 + bpf_event; 59 + 57 60 event_attr_op attr; 58 61 event_attr_op event_update; 59 62 event_op2 tracing_data;
-1
tools/perf/util/zlib.c
··· 6 6 #include <sys/mman.h> 7 7 #include <zlib.h> 8 8 #include <linux/compiler.h> 9 - #include <unistd.h> 10 9 11 10 #include "util/compress.h" 12 11 #include "util/util.h"