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

perf parse-events: Break out tracepoint and printing

Move print_*_events functions out of parse-events.c into a new
print-events.c. Move tracepoint code into tracepoint.c or
trace-event-info.c (sole user). This reduces the dependencies of
parse-events.c and makes it more amenable to being a library in the
future.

Remove some unnecessary definitions from parse-events.h. Fix a
checkpatch.pl warning on using unsigned rather than unsigned int. Fix
some line length warnings too.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20220729204217.250166-3-irogers@google.com
[ Add include linux/stddef.h before perf_events.h for systems where __always_inline isn't pulled in before used, such as older Alpine Linux ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
9b7c7728 32f457ab

+791 -738
+1 -1
tools/perf/builtin-list.c
··· 10 10 */ 11 11 #include "builtin.h" 12 12 13 - #include "util/parse-events.h" 13 + #include "util/print-events.h" 14 14 #include "util/pmu.h" 15 15 #include "util/pmu-hybrid.h" 16 16 #include "util/debug.h"
+1
tools/perf/builtin-lock.c
··· 16 16 #include <subcmd/pager.h> 17 17 #include <subcmd/parse-options.h> 18 18 #include "util/trace-event.h" 19 + #include "util/tracepoint.h" 19 20 20 21 #include "util/debug.h" 21 22 #include "util/session.h"
+1
tools/perf/builtin-timechart.c
··· 36 36 #include "util/data.h" 37 37 #include "util/debug.h" 38 38 #include "util/string2.h" 39 + #include "util/tracepoint.h" 39 40 #include <linux/err.h> 40 41 41 42 #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE
+1
tools/perf/builtin-trace.c
··· 53 53 #include "trace-event.h" 54 54 #include "util/parse-events.h" 55 55 #include "util/bpf-loader.h" 56 + #include "util/tracepoint.h" 56 57 #include "callchain.h" 57 58 #include "print_binary.h" 58 59 #include "string2.h"
+2
tools/perf/util/Build
··· 26 26 perf-y += memswap.o 27 27 perf-y += parse-events.o 28 28 perf-y += parse-events-hybrid.o 29 + perf-y += print-events.o 30 + perf-y += tracepoint.o 29 31 perf-y += perf_regs.o 30 32 perf-y += path.o 31 33 perf-y += print_binary.o
+7 -706
tools/perf/util/parse-events.c
··· 5 5 #include <dirent.h> 6 6 #include <errno.h> 7 7 #include <sys/ioctl.h> 8 - #include <sys/types.h> 9 - #include <sys/stat.h> 10 - #include <fcntl.h> 11 8 #include <sys/param.h> 12 9 #include "term.h" 13 - #include "build-id.h" 14 10 #include "evlist.h" 15 11 #include "evsel.h" 16 - #include <subcmd/pager.h> 17 12 #include <subcmd/parse-options.h> 18 13 #include "parse-events.h" 19 - #include <subcmd/exec-cmd.h> 20 14 #include "string2.h" 21 15 #include "strlist.h" 22 16 #include "bpf-loader.h" ··· 20 26 #include "parse-events-bison.h" 21 27 #include "parse-events-flex.h" 22 28 #include "pmu.h" 23 - #include "thread_map.h" 24 - #include "probe-file.h" 25 29 #include "asm/bug.h" 26 30 #include "util/parse-branch-options.h" 27 - #include "metricgroup.h" 28 31 #include "util/evsel_config.h" 29 32 #include "util/event.h" 30 - #include "util/pfm.h" 33 + #include "perf.h" 31 34 #include "util/parse-events-hybrid.h" 32 35 #include "util/pmu-hybrid.h" 33 - #include "perf.h" 36 + #include "tracepoint.h" 34 37 35 38 #define MAX_NAME_LEN 100 39 + 40 + struct perf_pmu_event_symbol { 41 + char *symbol; 42 + enum perf_pmu_event_symbol_type type; 43 + }; 36 44 37 45 #ifdef PARSER_DEBUG 38 46 extern int parse_events_debug; ··· 149 153 }, 150 154 }; 151 155 152 - struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { 153 - [PERF_TOOL_DURATION_TIME] = { 154 - .symbol = "duration_time", 155 - .alias = "", 156 - }, 157 - [PERF_TOOL_USER_TIME] = { 158 - .symbol = "user_time", 159 - .alias = "", 160 - }, 161 - [PERF_TOOL_SYSTEM_TIME] = { 162 - .symbol = "system_time", 163 - .alias = "", 164 - }, 165 - }; 166 - 167 156 #define __PERF_EVENT_FIELD(config, name) \ 168 157 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) 169 158 ··· 156 175 #define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) 157 176 #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 158 177 #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 159 - 160 - #define for_each_subsystem(sys_dir, sys_dirent) \ 161 - while ((sys_dirent = readdir(sys_dir)) != NULL) \ 162 - if (sys_dirent->d_type == DT_DIR && \ 163 - (strcmp(sys_dirent->d_name, ".")) && \ 164 - (strcmp(sys_dirent->d_name, ".."))) 165 - 166 - static int tp_event_has_id(const char *dir_path, struct dirent *evt_dir) 167 - { 168 - char evt_path[MAXPATHLEN]; 169 - int fd; 170 - 171 - snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name); 172 - fd = open(evt_path, O_RDONLY); 173 - if (fd < 0) 174 - return -EINVAL; 175 - close(fd); 176 - 177 - return 0; 178 - } 179 - 180 - #define for_each_event(dir_path, evt_dir, evt_dirent) \ 181 - while ((evt_dirent = readdir(evt_dir)) != NULL) \ 182 - if (evt_dirent->d_type == DT_DIR && \ 183 - (strcmp(evt_dirent->d_name, ".")) && \ 184 - (strcmp(evt_dirent->d_name, "..")) && \ 185 - (!tp_event_has_id(dir_path, evt_dirent))) 186 - 187 - #define MAX_EVENT_LENGTH 512 188 - 189 - struct tracepoint_path *tracepoint_id_to_path(u64 config) 190 - { 191 - struct tracepoint_path *path = NULL; 192 - DIR *sys_dir, *evt_dir; 193 - struct dirent *sys_dirent, *evt_dirent; 194 - char id_buf[24]; 195 - int fd; 196 - u64 id; 197 - char evt_path[MAXPATHLEN]; 198 - char *dir_path; 199 - 200 - sys_dir = tracing_events__opendir(); 201 - if (!sys_dir) 202 - return NULL; 203 - 204 - for_each_subsystem(sys_dir, sys_dirent) { 205 - dir_path = get_events_file(sys_dirent->d_name); 206 - if (!dir_path) 207 - continue; 208 - evt_dir = opendir(dir_path); 209 - if (!evt_dir) 210 - goto next; 211 - 212 - for_each_event(dir_path, evt_dir, evt_dirent) { 213 - 214 - scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, 215 - evt_dirent->d_name); 216 - fd = open(evt_path, O_RDONLY); 217 - if (fd < 0) 218 - continue; 219 - if (read(fd, id_buf, sizeof(id_buf)) < 0) { 220 - close(fd); 221 - continue; 222 - } 223 - close(fd); 224 - id = atoll(id_buf); 225 - if (id == config) { 226 - put_events_file(dir_path); 227 - closedir(evt_dir); 228 - closedir(sys_dir); 229 - path = zalloc(sizeof(*path)); 230 - if (!path) 231 - return NULL; 232 - if (asprintf(&path->system, "%.*s", MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) { 233 - free(path); 234 - return NULL; 235 - } 236 - if (asprintf(&path->name, "%.*s", MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) { 237 - zfree(&path->system); 238 - free(path); 239 - return NULL; 240 - } 241 - return path; 242 - } 243 - } 244 - closedir(evt_dir); 245 - next: 246 - put_events_file(dir_path); 247 - } 248 - 249 - closedir(sys_dir); 250 - return NULL; 251 - } 252 - 253 - struct tracepoint_path *tracepoint_name_to_path(const char *name) 254 - { 255 - struct tracepoint_path *path = zalloc(sizeof(*path)); 256 - char *str = strchr(name, ':'); 257 - 258 - if (path == NULL || str == NULL) { 259 - free(path); 260 - return NULL; 261 - } 262 - 263 - path->system = strndup(name, str - name); 264 - path->name = strdup(str+1); 265 - 266 - if (path->system == NULL || path->name == NULL) { 267 - zfree(&path->system); 268 - zfree(&path->name); 269 - zfree(&path); 270 - } 271 - 272 - return path; 273 - } 274 178 275 179 const char *event_type(int type) 276 180 { ··· 2529 2663 2530 2664 return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, 2531 2665 NULL); 2532 - } 2533 - 2534 - static const char * const event_type_descriptors[] = { 2535 - "Hardware event", 2536 - "Software event", 2537 - "Tracepoint event", 2538 - "Hardware cache event", 2539 - "Raw hardware event descriptor", 2540 - "Hardware breakpoint", 2541 - }; 2542 - 2543 - static int cmp_string(const void *a, const void *b) 2544 - { 2545 - const char * const *as = a; 2546 - const char * const *bs = b; 2547 - 2548 - return strcmp(*as, *bs); 2549 - } 2550 - 2551 - /* 2552 - * Print the events from <debugfs_mount_point>/tracing/events 2553 - */ 2554 - 2555 - void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 2556 - bool name_only) 2557 - { 2558 - DIR *sys_dir, *evt_dir; 2559 - struct dirent *sys_dirent, *evt_dirent; 2560 - char evt_path[MAXPATHLEN]; 2561 - char *dir_path; 2562 - char **evt_list = NULL; 2563 - unsigned int evt_i = 0, evt_num = 0; 2564 - bool evt_num_known = false; 2565 - 2566 - restart: 2567 - sys_dir = tracing_events__opendir(); 2568 - if (!sys_dir) 2569 - return; 2570 - 2571 - if (evt_num_known) { 2572 - evt_list = zalloc(sizeof(char *) * evt_num); 2573 - if (!evt_list) 2574 - goto out_close_sys_dir; 2575 - } 2576 - 2577 - for_each_subsystem(sys_dir, sys_dirent) { 2578 - if (subsys_glob != NULL && 2579 - !strglobmatch(sys_dirent->d_name, subsys_glob)) 2580 - continue; 2581 - 2582 - dir_path = get_events_file(sys_dirent->d_name); 2583 - if (!dir_path) 2584 - continue; 2585 - evt_dir = opendir(dir_path); 2586 - if (!evt_dir) 2587 - goto next; 2588 - 2589 - for_each_event(dir_path, evt_dir, evt_dirent) { 2590 - if (event_glob != NULL && 2591 - !strglobmatch(evt_dirent->d_name, event_glob)) 2592 - continue; 2593 - 2594 - if (!evt_num_known) { 2595 - evt_num++; 2596 - continue; 2597 - } 2598 - 2599 - snprintf(evt_path, MAXPATHLEN, "%s:%s", 2600 - sys_dirent->d_name, evt_dirent->d_name); 2601 - 2602 - evt_list[evt_i] = strdup(evt_path); 2603 - if (evt_list[evt_i] == NULL) { 2604 - put_events_file(dir_path); 2605 - goto out_close_evt_dir; 2606 - } 2607 - evt_i++; 2608 - } 2609 - closedir(evt_dir); 2610 - next: 2611 - put_events_file(dir_path); 2612 - } 2613 - closedir(sys_dir); 2614 - 2615 - if (!evt_num_known) { 2616 - evt_num_known = true; 2617 - goto restart; 2618 - } 2619 - qsort(evt_list, evt_num, sizeof(char *), cmp_string); 2620 - evt_i = 0; 2621 - while (evt_i < evt_num) { 2622 - if (name_only) { 2623 - printf("%s ", evt_list[evt_i++]); 2624 - continue; 2625 - } 2626 - printf(" %-50s [%s]\n", evt_list[evt_i++], 2627 - event_type_descriptors[PERF_TYPE_TRACEPOINT]); 2628 - } 2629 - if (evt_num && pager_in_use()) 2630 - printf("\n"); 2631 - 2632 - out_free: 2633 - evt_num = evt_i; 2634 - for (evt_i = 0; evt_i < evt_num; evt_i++) 2635 - zfree(&evt_list[evt_i]); 2636 - zfree(&evt_list); 2637 - return; 2638 - 2639 - out_close_evt_dir: 2640 - closedir(evt_dir); 2641 - out_close_sys_dir: 2642 - closedir(sys_dir); 2643 - 2644 - printf("FATAL: not enough memory to print %s\n", 2645 - event_type_descriptors[PERF_TYPE_TRACEPOINT]); 2646 - if (evt_list) 2647 - goto out_free; 2648 - } 2649 - 2650 - /* 2651 - * Check whether event is in <debugfs_mount_point>/tracing/events 2652 - */ 2653 - 2654 - int is_valid_tracepoint(const char *event_string) 2655 - { 2656 - DIR *sys_dir, *evt_dir; 2657 - struct dirent *sys_dirent, *evt_dirent; 2658 - char evt_path[MAXPATHLEN]; 2659 - char *dir_path; 2660 - 2661 - sys_dir = tracing_events__opendir(); 2662 - if (!sys_dir) 2663 - return 0; 2664 - 2665 - for_each_subsystem(sys_dir, sys_dirent) { 2666 - dir_path = get_events_file(sys_dirent->d_name); 2667 - if (!dir_path) 2668 - continue; 2669 - evt_dir = opendir(dir_path); 2670 - if (!evt_dir) 2671 - goto next; 2672 - 2673 - for_each_event(dir_path, evt_dir, evt_dirent) { 2674 - snprintf(evt_path, MAXPATHLEN, "%s:%s", 2675 - sys_dirent->d_name, evt_dirent->d_name); 2676 - if (!strcmp(evt_path, event_string)) { 2677 - closedir(evt_dir); 2678 - closedir(sys_dir); 2679 - return 1; 2680 - } 2681 - } 2682 - closedir(evt_dir); 2683 - next: 2684 - put_events_file(dir_path); 2685 - } 2686 - closedir(sys_dir); 2687 - return 0; 2688 - } 2689 - 2690 - static bool is_event_supported(u8 type, u64 config) 2691 - { 2692 - bool ret = true; 2693 - int open_return; 2694 - struct evsel *evsel; 2695 - struct perf_event_attr attr = { 2696 - .type = type, 2697 - .config = config, 2698 - .disabled = 1, 2699 - }; 2700 - struct perf_thread_map *tmap = thread_map__new_by_tid(0); 2701 - 2702 - if (tmap == NULL) 2703 - return false; 2704 - 2705 - evsel = evsel__new(&attr); 2706 - if (evsel) { 2707 - open_return = evsel__open(evsel, NULL, tmap); 2708 - ret = open_return >= 0; 2709 - 2710 - if (open_return == -EACCES) { 2711 - /* 2712 - * This happens if the paranoid value 2713 - * /proc/sys/kernel/perf_event_paranoid is set to 2 2714 - * Re-run with exclude_kernel set; we don't do that 2715 - * by default as some ARM machines do not support it. 2716 - * 2717 - */ 2718 - evsel->core.attr.exclude_kernel = 1; 2719 - ret = evsel__open(evsel, NULL, tmap) >= 0; 2720 - } 2721 - evsel__delete(evsel); 2722 - } 2723 - 2724 - perf_thread_map__put(tmap); 2725 - return ret; 2726 - } 2727 - 2728 - void print_sdt_events(const char *subsys_glob, const char *event_glob, 2729 - bool name_only) 2730 - { 2731 - struct probe_cache *pcache; 2732 - struct probe_cache_entry *ent; 2733 - struct strlist *bidlist, *sdtlist; 2734 - struct strlist_config cfg = {.dont_dupstr = true}; 2735 - struct str_node *nd, *nd2; 2736 - char *buf, *path, *ptr = NULL; 2737 - bool show_detail = false; 2738 - int ret; 2739 - 2740 - sdtlist = strlist__new(NULL, &cfg); 2741 - if (!sdtlist) { 2742 - pr_debug("Failed to allocate new strlist for SDT\n"); 2743 - return; 2744 - } 2745 - bidlist = build_id_cache__list_all(true); 2746 - if (!bidlist) { 2747 - pr_debug("Failed to get buildids: %d\n", errno); 2748 - return; 2749 - } 2750 - strlist__for_each_entry(nd, bidlist) { 2751 - pcache = probe_cache__new(nd->s, NULL); 2752 - if (!pcache) 2753 - continue; 2754 - list_for_each_entry(ent, &pcache->entries, node) { 2755 - if (!ent->sdt) 2756 - continue; 2757 - if (subsys_glob && 2758 - !strglobmatch(ent->pev.group, subsys_glob)) 2759 - continue; 2760 - if (event_glob && 2761 - !strglobmatch(ent->pev.event, event_glob)) 2762 - continue; 2763 - ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, 2764 - ent->pev.event, nd->s); 2765 - if (ret > 0) 2766 - strlist__add(sdtlist, buf); 2767 - } 2768 - probe_cache__delete(pcache); 2769 - } 2770 - strlist__delete(bidlist); 2771 - 2772 - strlist__for_each_entry(nd, sdtlist) { 2773 - buf = strchr(nd->s, '@'); 2774 - if (buf) 2775 - *(buf++) = '\0'; 2776 - if (name_only) { 2777 - printf("%s ", nd->s); 2778 - continue; 2779 - } 2780 - nd2 = strlist__next(nd); 2781 - if (nd2) { 2782 - ptr = strchr(nd2->s, '@'); 2783 - if (ptr) 2784 - *ptr = '\0'; 2785 - if (strcmp(nd->s, nd2->s) == 0) 2786 - show_detail = true; 2787 - } 2788 - if (show_detail) { 2789 - path = build_id_cache__origname(buf); 2790 - ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); 2791 - if (ret > 0) { 2792 - printf(" %-50s [%s]\n", buf, "SDT event"); 2793 - free(buf); 2794 - } 2795 - free(path); 2796 - } else 2797 - printf(" %-50s [%s]\n", nd->s, "SDT event"); 2798 - if (nd2) { 2799 - if (strcmp(nd->s, nd2->s) != 0) 2800 - show_detail = false; 2801 - if (ptr) 2802 - *ptr = '@'; 2803 - } 2804 - } 2805 - strlist__delete(sdtlist); 2806 - } 2807 - 2808 - int print_hwcache_events(const char *event_glob, bool name_only) 2809 - { 2810 - unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0; 2811 - char name[64], new_name[128]; 2812 - char **evt_list = NULL, **evt_pmus = NULL; 2813 - bool evt_num_known = false; 2814 - struct perf_pmu *pmu = NULL; 2815 - 2816 - if (perf_pmu__has_hybrid()) { 2817 - npmus = perf_pmu__hybrid_pmu_num(); 2818 - evt_pmus = zalloc(sizeof(char *) * npmus); 2819 - if (!evt_pmus) 2820 - goto out_enomem; 2821 - } 2822 - 2823 - restart: 2824 - if (evt_num_known) { 2825 - evt_list = zalloc(sizeof(char *) * evt_num); 2826 - if (!evt_list) 2827 - goto out_enomem; 2828 - } 2829 - 2830 - for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 2831 - for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 2832 - /* skip invalid cache type */ 2833 - if (!evsel__is_cache_op_valid(type, op)) 2834 - continue; 2835 - 2836 - for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 2837 - unsigned int hybrid_supported = 0, j; 2838 - bool supported; 2839 - 2840 - __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); 2841 - if (event_glob != NULL && !strglobmatch(name, event_glob)) 2842 - continue; 2843 - 2844 - if (!perf_pmu__has_hybrid()) { 2845 - if (!is_event_supported(PERF_TYPE_HW_CACHE, 2846 - type | (op << 8) | (i << 16))) { 2847 - continue; 2848 - } 2849 - } else { 2850 - perf_pmu__for_each_hybrid_pmu(pmu) { 2851 - if (!evt_num_known) { 2852 - evt_num++; 2853 - continue; 2854 - } 2855 - 2856 - supported = is_event_supported( 2857 - PERF_TYPE_HW_CACHE, 2858 - type | (op << 8) | (i << 16) | 2859 - ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)); 2860 - if (supported) { 2861 - snprintf(new_name, sizeof(new_name), "%s/%s/", 2862 - pmu->name, name); 2863 - evt_pmus[hybrid_supported] = strdup(new_name); 2864 - hybrid_supported++; 2865 - } 2866 - } 2867 - 2868 - if (hybrid_supported == 0) 2869 - continue; 2870 - } 2871 - 2872 - if (!evt_num_known) { 2873 - evt_num++; 2874 - continue; 2875 - } 2876 - 2877 - if ((hybrid_supported == 0) || 2878 - (hybrid_supported == npmus)) { 2879 - evt_list[evt_i] = strdup(name); 2880 - if (npmus > 0) { 2881 - for (j = 0; j < npmus; j++) 2882 - zfree(&evt_pmus[j]); 2883 - } 2884 - } else { 2885 - for (j = 0; j < hybrid_supported; j++) { 2886 - evt_list[evt_i++] = evt_pmus[j]; 2887 - evt_pmus[j] = NULL; 2888 - } 2889 - continue; 2890 - } 2891 - 2892 - if (evt_list[evt_i] == NULL) 2893 - goto out_enomem; 2894 - evt_i++; 2895 - } 2896 - } 2897 - } 2898 - 2899 - if (!evt_num_known) { 2900 - evt_num_known = true; 2901 - goto restart; 2902 - } 2903 - 2904 - for (evt_i = 0; evt_i < evt_num; evt_i++) { 2905 - if (!evt_list[evt_i]) 2906 - break; 2907 - } 2908 - 2909 - evt_num = evt_i; 2910 - qsort(evt_list, evt_num, sizeof(char *), cmp_string); 2911 - evt_i = 0; 2912 - while (evt_i < evt_num) { 2913 - if (name_only) { 2914 - printf("%s ", evt_list[evt_i++]); 2915 - continue; 2916 - } 2917 - printf(" %-50s [%s]\n", evt_list[evt_i++], 2918 - event_type_descriptors[PERF_TYPE_HW_CACHE]); 2919 - } 2920 - if (evt_num && pager_in_use()) 2921 - printf("\n"); 2922 - 2923 - out_free: 2924 - evt_num = evt_i; 2925 - for (evt_i = 0; evt_i < evt_num; evt_i++) 2926 - zfree(&evt_list[evt_i]); 2927 - zfree(&evt_list); 2928 - 2929 - for (evt_i = 0; evt_i < npmus; evt_i++) 2930 - zfree(&evt_pmus[evt_i]); 2931 - zfree(&evt_pmus); 2932 - return evt_num; 2933 - 2934 - out_enomem: 2935 - printf("FATAL: not enough memory to print %s\n", event_type_descriptors[PERF_TYPE_HW_CACHE]); 2936 - if (evt_list) 2937 - goto out_free; 2938 - return evt_num; 2939 - } 2940 - 2941 - static void print_tool_event(const struct event_symbol *syms, const char *event_glob, 2942 - bool name_only) 2943 - { 2944 - if (syms->symbol == NULL) 2945 - return; 2946 - 2947 - if (event_glob && !(strglobmatch(syms->symbol, event_glob) || 2948 - (syms->alias && strglobmatch(syms->alias, event_glob)))) 2949 - return; 2950 - 2951 - if (name_only) 2952 - printf("%s ", syms->symbol); 2953 - else { 2954 - char name[MAX_NAME_LEN]; 2955 - if (syms->alias && strlen(syms->alias)) 2956 - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 2957 - else 2958 - strlcpy(name, syms->symbol, MAX_NAME_LEN); 2959 - printf(" %-50s [%s]\n", name, "Tool event"); 2960 - } 2961 - } 2962 - 2963 - void print_tool_events(const char *event_glob, bool name_only) 2964 - { 2965 - // Start at 1 because the first enum entry symbols no tool event 2966 - for (int i = 1; i < PERF_TOOL_MAX; ++i) { 2967 - print_tool_event(event_symbols_tool + i, event_glob, name_only); 2968 - } 2969 - if (pager_in_use()) 2970 - printf("\n"); 2971 - } 2972 - 2973 - void print_symbol_events(const char *event_glob, unsigned type, 2974 - struct event_symbol *syms, unsigned max, 2975 - bool name_only) 2976 - { 2977 - unsigned int i, evt_i = 0, evt_num = 0; 2978 - char name[MAX_NAME_LEN]; 2979 - char **evt_list = NULL; 2980 - bool evt_num_known = false; 2981 - 2982 - restart: 2983 - if (evt_num_known) { 2984 - evt_list = zalloc(sizeof(char *) * evt_num); 2985 - if (!evt_list) 2986 - goto out_enomem; 2987 - syms -= max; 2988 - } 2989 - 2990 - for (i = 0; i < max; i++, syms++) { 2991 - /* 2992 - * New attr.config still not supported here, the latest 2993 - * example was PERF_COUNT_SW_CGROUP_SWITCHES 2994 - */ 2995 - if (syms->symbol == NULL) 2996 - continue; 2997 - 2998 - if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) || 2999 - (syms->alias && strglobmatch(syms->alias, event_glob)))) 3000 - continue; 3001 - 3002 - if (!is_event_supported(type, i)) 3003 - continue; 3004 - 3005 - if (!evt_num_known) { 3006 - evt_num++; 3007 - continue; 3008 - } 3009 - 3010 - if (!name_only && strlen(syms->alias)) 3011 - snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 3012 - else 3013 - strlcpy(name, syms->symbol, MAX_NAME_LEN); 3014 - 3015 - evt_list[evt_i] = strdup(name); 3016 - if (evt_list[evt_i] == NULL) 3017 - goto out_enomem; 3018 - evt_i++; 3019 - } 3020 - 3021 - if (!evt_num_known) { 3022 - evt_num_known = true; 3023 - goto restart; 3024 - } 3025 - qsort(evt_list, evt_num, sizeof(char *), cmp_string); 3026 - evt_i = 0; 3027 - while (evt_i < evt_num) { 3028 - if (name_only) { 3029 - printf("%s ", evt_list[evt_i++]); 3030 - continue; 3031 - } 3032 - printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]); 3033 - } 3034 - if (evt_num && pager_in_use()) 3035 - printf("\n"); 3036 - 3037 - out_free: 3038 - evt_num = evt_i; 3039 - for (evt_i = 0; evt_i < evt_num; evt_i++) 3040 - zfree(&evt_list[evt_i]); 3041 - zfree(&evt_list); 3042 - return; 3043 - 3044 - out_enomem: 3045 - printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]); 3046 - if (evt_list) 3047 - goto out_free; 3048 - } 3049 - 3050 - /* 3051 - * Print the help text for the event symbols: 3052 - */ 3053 - void print_events(const char *event_glob, bool name_only, bool quiet_flag, 3054 - bool long_desc, bool details_flag, bool deprecated, 3055 - const char *pmu_name) 3056 - { 3057 - print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 3058 - event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 3059 - 3060 - print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, 3061 - event_symbols_sw, PERF_COUNT_SW_MAX, name_only); 3062 - print_tool_events(event_glob, name_only); 3063 - 3064 - print_hwcache_events(event_glob, name_only); 3065 - 3066 - print_pmu_events(event_glob, name_only, quiet_flag, long_desc, 3067 - details_flag, deprecated, pmu_name); 3068 - 3069 - if (event_glob != NULL) 3070 - return; 3071 - 3072 - if (!name_only) { 3073 - printf(" %-50s [%s]\n", 3074 - "rNNN", 3075 - event_type_descriptors[PERF_TYPE_RAW]); 3076 - printf(" %-50s [%s]\n", 3077 - "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 3078 - event_type_descriptors[PERF_TYPE_RAW]); 3079 - if (pager_in_use()) 3080 - printf(" (see 'man perf-list' on how to encode it)\n\n"); 3081 - 3082 - printf(" %-50s [%s]\n", 3083 - "mem:<addr>[/len][:access]", 3084 - event_type_descriptors[PERF_TYPE_BREAKPOINT]); 3085 - if (pager_in_use()) 3086 - printf("\n"); 3087 - } 3088 - 3089 - print_tracepoint_events(NULL, NULL, name_only); 3090 - 3091 - print_sdt_events(NULL, NULL, name_only); 3092 - 3093 - metricgroup__print(true, true, NULL, name_only, details_flag, 3094 - pmu_name); 3095 - 3096 - print_libpfm_events(name_only, long_desc); 3097 2666 } 3098 2667 3099 2668 int parse_events__is_hardcoded_term(struct parse_events_term *term)
-31
tools/perf/util/parse-events.h
··· 11 11 #include <linux/perf_event.h> 12 12 #include <string.h> 13 13 14 - struct list_head; 15 14 struct evsel; 16 15 struct evlist; 17 16 struct parse_events_error; ··· 18 19 struct option; 19 20 struct perf_pmu; 20 21 21 - struct tracepoint_path { 22 - char *system; 23 - char *name; 24 - struct tracepoint_path *next; 25 - }; 26 - 27 - struct tracepoint_path *tracepoint_id_to_path(u64 config); 28 - struct tracepoint_path *tracepoint_name_to_path(const char *name); 29 22 bool have_tracepoints(struct list_head *evlist); 30 23 31 24 const char *event_type(int type); ··· 37 46 int parse_filter(const struct option *opt, const char *str, int unset); 38 47 int exclude_perf(const struct option *opt, const char *arg, int unset); 39 48 40 - #define EVENTS_HELP_MAX (128*1024) 41 - 42 49 enum perf_pmu_event_symbol_type { 43 50 PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */ 44 51 PMU_EVENT_SYMBOL, /* normal style PMU event */ 45 52 PMU_EVENT_SYMBOL_PREFIX, /* prefix of pre-suf style event */ 46 53 PMU_EVENT_SYMBOL_SUFFIX, /* suffix of pre-suf style event */ 47 54 PMU_EVENT_SYMBOL_SUFFIX2, /* suffix of pre-suf2 style event */ 48 - }; 49 - 50 - struct perf_pmu_event_symbol { 51 - char *symbol; 52 - enum perf_pmu_event_symbol_type type; 53 55 }; 54 56 55 57 enum { ··· 203 219 void parse_events_evlist_error(struct parse_events_state *parse_state, 204 220 int idx, const char *str); 205 221 206 - void print_events(const char *event_glob, bool name_only, bool quiet, 207 - bool long_desc, bool details_flag, bool deprecated, 208 - const char *pmu_name); 209 - 210 222 struct event_symbol { 211 223 const char *symbol; 212 224 const char *alias; 213 225 }; 214 226 extern struct event_symbol event_symbols_hw[]; 215 227 extern struct event_symbol event_symbols_sw[]; 216 - void print_symbol_events(const char *event_glob, unsigned type, 217 - struct event_symbol *syms, unsigned max, 218 - bool name_only); 219 - void print_tool_events(const char *event_glob, bool name_only); 220 - void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 221 - bool name_only); 222 - int print_hwcache_events(const char *event_glob, bool name_only); 223 - void print_sdt_events(const char *subsys_glob, const char *event_glob, 224 - bool name_only); 225 - int is_valid_tracepoint(const char *event_string); 226 228 227 - int valid_event_mount(const char *eventfs); 228 229 char *parse_events_formats_error_string(char *additional_terms); 229 230 230 231 void parse_events_error__init(struct parse_events_error *err);
+572
tools/perf/util/print-events.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <dirent.h> 3 + #include <errno.h> 4 + #include <stdio.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + #include <sys/param.h> 8 + 9 + #include <api/fs/tracing_path.h> 10 + #include <linux/stddef.h> 11 + #include <linux/perf_event.h> 12 + #include <linux/zalloc.h> 13 + #include <subcmd/pager.h> 14 + 15 + #include "build-id.h" 16 + #include "debug.h" 17 + #include "evsel.h" 18 + #include "metricgroup.h" 19 + #include "parse-events.h" 20 + #include "pmu.h" 21 + #include "print-events.h" 22 + #include "probe-file.h" 23 + #include "string2.h" 24 + #include "strlist.h" 25 + #include "thread_map.h" 26 + #include "tracepoint.h" 27 + #include "pfm.h" 28 + #include "pmu-hybrid.h" 29 + 30 + #define MAX_NAME_LEN 100 31 + 32 + static const char * const event_type_descriptors[] = { 33 + "Hardware event", 34 + "Software event", 35 + "Tracepoint event", 36 + "Hardware cache event", 37 + "Raw hardware event descriptor", 38 + "Hardware breakpoint", 39 + }; 40 + 41 + static const struct event_symbol event_symbols_tool[PERF_TOOL_MAX] = { 42 + [PERF_TOOL_DURATION_TIME] = { 43 + .symbol = "duration_time", 44 + .alias = "", 45 + }, 46 + [PERF_TOOL_USER_TIME] = { 47 + .symbol = "user_time", 48 + .alias = "", 49 + }, 50 + [PERF_TOOL_SYSTEM_TIME] = { 51 + .symbol = "system_time", 52 + .alias = "", 53 + }, 54 + }; 55 + 56 + static int cmp_string(const void *a, const void *b) 57 + { 58 + const char * const *as = a; 59 + const char * const *bs = b; 60 + 61 + return strcmp(*as, *bs); 62 + } 63 + 64 + /* 65 + * Print the events from <debugfs_mount_point>/tracing/events 66 + */ 67 + void print_tracepoint_events(const char *subsys_glob, 68 + const char *event_glob, bool name_only) 69 + { 70 + DIR *sys_dir, *evt_dir; 71 + struct dirent *sys_dirent, *evt_dirent; 72 + char evt_path[MAXPATHLEN]; 73 + char *dir_path; 74 + char **evt_list = NULL; 75 + unsigned int evt_i = 0, evt_num = 0; 76 + bool evt_num_known = false; 77 + 78 + restart: 79 + sys_dir = tracing_events__opendir(); 80 + if (!sys_dir) 81 + return; 82 + 83 + if (evt_num_known) { 84 + evt_list = zalloc(sizeof(char *) * evt_num); 85 + if (!evt_list) 86 + goto out_close_sys_dir; 87 + } 88 + 89 + for_each_subsystem(sys_dir, sys_dirent) { 90 + if (subsys_glob != NULL && 91 + !strglobmatch(sys_dirent->d_name, subsys_glob)) 92 + continue; 93 + 94 + dir_path = get_events_file(sys_dirent->d_name); 95 + if (!dir_path) 96 + continue; 97 + evt_dir = opendir(dir_path); 98 + if (!evt_dir) 99 + goto next; 100 + 101 + for_each_event(dir_path, evt_dir, evt_dirent) { 102 + if (event_glob != NULL && 103 + !strglobmatch(evt_dirent->d_name, event_glob)) 104 + continue; 105 + 106 + if (!evt_num_known) { 107 + evt_num++; 108 + continue; 109 + } 110 + 111 + snprintf(evt_path, MAXPATHLEN, "%s:%s", 112 + sys_dirent->d_name, evt_dirent->d_name); 113 + 114 + evt_list[evt_i] = strdup(evt_path); 115 + if (evt_list[evt_i] == NULL) { 116 + put_events_file(dir_path); 117 + goto out_close_evt_dir; 118 + } 119 + evt_i++; 120 + } 121 + closedir(evt_dir); 122 + next: 123 + put_events_file(dir_path); 124 + } 125 + closedir(sys_dir); 126 + 127 + if (!evt_num_known) { 128 + evt_num_known = true; 129 + goto restart; 130 + } 131 + qsort(evt_list, evt_num, sizeof(char *), cmp_string); 132 + evt_i = 0; 133 + while (evt_i < evt_num) { 134 + if (name_only) { 135 + printf("%s ", evt_list[evt_i++]); 136 + continue; 137 + } 138 + printf(" %-50s [%s]\n", evt_list[evt_i++], 139 + event_type_descriptors[PERF_TYPE_TRACEPOINT]); 140 + } 141 + if (evt_num && pager_in_use()) 142 + printf("\n"); 143 + 144 + out_free: 145 + evt_num = evt_i; 146 + for (evt_i = 0; evt_i < evt_num; evt_i++) 147 + zfree(&evt_list[evt_i]); 148 + zfree(&evt_list); 149 + return; 150 + 151 + out_close_evt_dir: 152 + closedir(evt_dir); 153 + out_close_sys_dir: 154 + closedir(sys_dir); 155 + 156 + printf("FATAL: not enough memory to print %s\n", 157 + event_type_descriptors[PERF_TYPE_TRACEPOINT]); 158 + if (evt_list) 159 + goto out_free; 160 + } 161 + 162 + void print_sdt_events(const char *subsys_glob, const char *event_glob, 163 + bool name_only) 164 + { 165 + struct probe_cache *pcache; 166 + struct probe_cache_entry *ent; 167 + struct strlist *bidlist, *sdtlist; 168 + struct strlist_config cfg = {.dont_dupstr = true}; 169 + struct str_node *nd, *nd2; 170 + char *buf, *path, *ptr = NULL; 171 + bool show_detail = false; 172 + int ret; 173 + 174 + sdtlist = strlist__new(NULL, &cfg); 175 + if (!sdtlist) { 176 + pr_debug("Failed to allocate new strlist for SDT\n"); 177 + return; 178 + } 179 + bidlist = build_id_cache__list_all(true); 180 + if (!bidlist) { 181 + pr_debug("Failed to get buildids: %d\n", errno); 182 + return; 183 + } 184 + strlist__for_each_entry(nd, bidlist) { 185 + pcache = probe_cache__new(nd->s, NULL); 186 + if (!pcache) 187 + continue; 188 + list_for_each_entry(ent, &pcache->entries, node) { 189 + if (!ent->sdt) 190 + continue; 191 + if (subsys_glob && 192 + !strglobmatch(ent->pev.group, subsys_glob)) 193 + continue; 194 + if (event_glob && 195 + !strglobmatch(ent->pev.event, event_glob)) 196 + continue; 197 + ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, 198 + ent->pev.event, nd->s); 199 + if (ret > 0) 200 + strlist__add(sdtlist, buf); 201 + } 202 + probe_cache__delete(pcache); 203 + } 204 + strlist__delete(bidlist); 205 + 206 + strlist__for_each_entry(nd, sdtlist) { 207 + buf = strchr(nd->s, '@'); 208 + if (buf) 209 + *(buf++) = '\0'; 210 + if (name_only) { 211 + printf("%s ", nd->s); 212 + continue; 213 + } 214 + nd2 = strlist__next(nd); 215 + if (nd2) { 216 + ptr = strchr(nd2->s, '@'); 217 + if (ptr) 218 + *ptr = '\0'; 219 + if (strcmp(nd->s, nd2->s) == 0) 220 + show_detail = true; 221 + } 222 + if (show_detail) { 223 + path = build_id_cache__origname(buf); 224 + ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); 225 + if (ret > 0) { 226 + printf(" %-50s [%s]\n", buf, "SDT event"); 227 + free(buf); 228 + } 229 + free(path); 230 + } else 231 + printf(" %-50s [%s]\n", nd->s, "SDT event"); 232 + if (nd2) { 233 + if (strcmp(nd->s, nd2->s) != 0) 234 + show_detail = false; 235 + if (ptr) 236 + *ptr = '@'; 237 + } 238 + } 239 + strlist__delete(sdtlist); 240 + } 241 + 242 + static bool is_event_supported(u8 type, unsigned int config) 243 + { 244 + bool ret = true; 245 + int open_return; 246 + struct evsel *evsel; 247 + struct perf_event_attr attr = { 248 + .type = type, 249 + .config = config, 250 + .disabled = 1, 251 + }; 252 + struct perf_thread_map *tmap = thread_map__new_by_tid(0); 253 + 254 + if (tmap == NULL) 255 + return false; 256 + 257 + evsel = evsel__new(&attr); 258 + if (evsel) { 259 + open_return = evsel__open(evsel, NULL, tmap); 260 + ret = open_return >= 0; 261 + 262 + if (open_return == -EACCES) { 263 + /* 264 + * This happens if the paranoid value 265 + * /proc/sys/kernel/perf_event_paranoid is set to 2 266 + * Re-run with exclude_kernel set; we don't do that 267 + * by default as some ARM machines do not support it. 268 + * 269 + */ 270 + evsel->core.attr.exclude_kernel = 1; 271 + ret = evsel__open(evsel, NULL, tmap) >= 0; 272 + } 273 + evsel__delete(evsel); 274 + } 275 + 276 + perf_thread_map__put(tmap); 277 + return ret; 278 + } 279 + 280 + int print_hwcache_events(const char *event_glob, bool name_only) 281 + { 282 + unsigned int type, op, i, evt_i = 0, evt_num = 0, npmus = 0; 283 + char name[64], new_name[128]; 284 + char **evt_list = NULL, **evt_pmus = NULL; 285 + bool evt_num_known = false; 286 + struct perf_pmu *pmu = NULL; 287 + 288 + if (perf_pmu__has_hybrid()) { 289 + npmus = perf_pmu__hybrid_pmu_num(); 290 + evt_pmus = zalloc(sizeof(char *) * npmus); 291 + if (!evt_pmus) 292 + goto out_enomem; 293 + } 294 + 295 + restart: 296 + if (evt_num_known) { 297 + evt_list = zalloc(sizeof(char *) * evt_num); 298 + if (!evt_list) 299 + goto out_enomem; 300 + } 301 + 302 + for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 303 + for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 304 + /* skip invalid cache type */ 305 + if (!evsel__is_cache_op_valid(type, op)) 306 + continue; 307 + 308 + for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 309 + unsigned int hybrid_supported = 0, j; 310 + bool supported; 311 + 312 + __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); 313 + if (event_glob != NULL && !strglobmatch(name, event_glob)) 314 + continue; 315 + 316 + if (!perf_pmu__has_hybrid()) { 317 + if (!is_event_supported(PERF_TYPE_HW_CACHE, 318 + type | (op << 8) | (i << 16))) { 319 + continue; 320 + } 321 + } else { 322 + perf_pmu__for_each_hybrid_pmu(pmu) { 323 + if (!evt_num_known) { 324 + evt_num++; 325 + continue; 326 + } 327 + 328 + supported = is_event_supported( 329 + PERF_TYPE_HW_CACHE, 330 + type | (op << 8) | (i << 16) | 331 + ((__u64)pmu->type << PERF_PMU_TYPE_SHIFT)); 332 + if (supported) { 333 + snprintf(new_name, sizeof(new_name), 334 + "%s/%s/", pmu->name, name); 335 + evt_pmus[hybrid_supported] = 336 + strdup(new_name); 337 + hybrid_supported++; 338 + } 339 + } 340 + 341 + if (hybrid_supported == 0) 342 + continue; 343 + } 344 + 345 + if (!evt_num_known) { 346 + evt_num++; 347 + continue; 348 + } 349 + 350 + if ((hybrid_supported == 0) || 351 + (hybrid_supported == npmus)) { 352 + evt_list[evt_i] = strdup(name); 353 + if (npmus > 0) { 354 + for (j = 0; j < npmus; j++) 355 + zfree(&evt_pmus[j]); 356 + } 357 + } else { 358 + for (j = 0; j < hybrid_supported; j++) { 359 + evt_list[evt_i++] = evt_pmus[j]; 360 + evt_pmus[j] = NULL; 361 + } 362 + continue; 363 + } 364 + 365 + if (evt_list[evt_i] == NULL) 366 + goto out_enomem; 367 + evt_i++; 368 + } 369 + } 370 + } 371 + 372 + if (!evt_num_known) { 373 + evt_num_known = true; 374 + goto restart; 375 + } 376 + 377 + for (evt_i = 0; evt_i < evt_num; evt_i++) { 378 + if (!evt_list[evt_i]) 379 + break; 380 + } 381 + 382 + evt_num = evt_i; 383 + qsort(evt_list, evt_num, sizeof(char *), cmp_string); 384 + evt_i = 0; 385 + while (evt_i < evt_num) { 386 + if (name_only) { 387 + printf("%s ", evt_list[evt_i++]); 388 + continue; 389 + } 390 + printf(" %-50s [%s]\n", evt_list[evt_i++], 391 + event_type_descriptors[PERF_TYPE_HW_CACHE]); 392 + } 393 + if (evt_num && pager_in_use()) 394 + printf("\n"); 395 + 396 + out_free: 397 + evt_num = evt_i; 398 + for (evt_i = 0; evt_i < evt_num; evt_i++) 399 + zfree(&evt_list[evt_i]); 400 + zfree(&evt_list); 401 + 402 + for (evt_i = 0; evt_i < npmus; evt_i++) 403 + zfree(&evt_pmus[evt_i]); 404 + zfree(&evt_pmus); 405 + return evt_num; 406 + 407 + out_enomem: 408 + printf("FATAL: not enough memory to print %s\n", 409 + event_type_descriptors[PERF_TYPE_HW_CACHE]); 410 + if (evt_list) 411 + goto out_free; 412 + return evt_num; 413 + } 414 + 415 + static void print_tool_event(const struct event_symbol *syms, const char *event_glob, 416 + bool name_only) 417 + { 418 + if (syms->symbol == NULL) 419 + return; 420 + 421 + if (event_glob && !(strglobmatch(syms->symbol, event_glob) || 422 + (syms->alias && strglobmatch(syms->alias, event_glob)))) 423 + return; 424 + 425 + if (name_only) 426 + printf("%s ", syms->symbol); 427 + else { 428 + char name[MAX_NAME_LEN]; 429 + 430 + if (syms->alias && strlen(syms->alias)) 431 + snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 432 + else 433 + strlcpy(name, syms->symbol, MAX_NAME_LEN); 434 + printf(" %-50s [%s]\n", name, "Tool event"); 435 + } 436 + } 437 + 438 + void print_tool_events(const char *event_glob, bool name_only) 439 + { 440 + // Start at 1 because the first enum entry means no tool event. 441 + for (int i = 1; i < PERF_TOOL_MAX; ++i) 442 + print_tool_event(event_symbols_tool + i, event_glob, name_only); 443 + 444 + if (pager_in_use()) 445 + printf("\n"); 446 + } 447 + 448 + void print_symbol_events(const char *event_glob, unsigned int type, 449 + struct event_symbol *syms, unsigned int max, 450 + bool name_only) 451 + { 452 + unsigned int i, evt_i = 0, evt_num = 0; 453 + char name[MAX_NAME_LEN]; 454 + char **evt_list = NULL; 455 + bool evt_num_known = false; 456 + 457 + restart: 458 + if (evt_num_known) { 459 + evt_list = zalloc(sizeof(char *) * evt_num); 460 + if (!evt_list) 461 + goto out_enomem; 462 + syms -= max; 463 + } 464 + 465 + for (i = 0; i < max; i++, syms++) { 466 + /* 467 + * New attr.config still not supported here, the latest 468 + * example was PERF_COUNT_SW_CGROUP_SWITCHES 469 + */ 470 + if (syms->symbol == NULL) 471 + continue; 472 + 473 + if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) || 474 + (syms->alias && strglobmatch(syms->alias, event_glob)))) 475 + continue; 476 + 477 + if (!is_event_supported(type, i)) 478 + continue; 479 + 480 + if (!evt_num_known) { 481 + evt_num++; 482 + continue; 483 + } 484 + 485 + if (!name_only && strlen(syms->alias)) 486 + snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 487 + else 488 + strlcpy(name, syms->symbol, MAX_NAME_LEN); 489 + 490 + evt_list[evt_i] = strdup(name); 491 + if (evt_list[evt_i] == NULL) 492 + goto out_enomem; 493 + evt_i++; 494 + } 495 + 496 + if (!evt_num_known) { 497 + evt_num_known = true; 498 + goto restart; 499 + } 500 + qsort(evt_list, evt_num, sizeof(char *), cmp_string); 501 + evt_i = 0; 502 + while (evt_i < evt_num) { 503 + if (name_only) { 504 + printf("%s ", evt_list[evt_i++]); 505 + continue; 506 + } 507 + printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]); 508 + } 509 + if (evt_num && pager_in_use()) 510 + printf("\n"); 511 + 512 + out_free: 513 + evt_num = evt_i; 514 + for (evt_i = 0; evt_i < evt_num; evt_i++) 515 + zfree(&evt_list[evt_i]); 516 + zfree(&evt_list); 517 + return; 518 + 519 + out_enomem: 520 + printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]); 521 + if (evt_list) 522 + goto out_free; 523 + } 524 + 525 + /* 526 + * Print the help text for the event symbols: 527 + */ 528 + void print_events(const char *event_glob, bool name_only, bool quiet_flag, 529 + bool long_desc, bool details_flag, bool deprecated, 530 + const char *pmu_name) 531 + { 532 + print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 533 + event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 534 + 535 + print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, 536 + event_symbols_sw, PERF_COUNT_SW_MAX, name_only); 537 + print_tool_events(event_glob, name_only); 538 + 539 + print_hwcache_events(event_glob, name_only); 540 + 541 + print_pmu_events(event_glob, name_only, quiet_flag, long_desc, 542 + details_flag, deprecated, pmu_name); 543 + 544 + if (event_glob != NULL) 545 + return; 546 + 547 + if (!name_only) { 548 + printf(" %-50s [%s]\n", 549 + "rNNN", 550 + event_type_descriptors[PERF_TYPE_RAW]); 551 + printf(" %-50s [%s]\n", 552 + "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 553 + event_type_descriptors[PERF_TYPE_RAW]); 554 + if (pager_in_use()) 555 + printf(" (see 'man perf-list' on how to encode it)\n\n"); 556 + 557 + printf(" %-50s [%s]\n", 558 + "mem:<addr>[/len][:access]", 559 + event_type_descriptors[PERF_TYPE_BREAKPOINT]); 560 + if (pager_in_use()) 561 + printf("\n"); 562 + } 563 + 564 + print_tracepoint_events(NULL, NULL, name_only); 565 + 566 + print_sdt_events(NULL, NULL, name_only); 567 + 568 + metricgroup__print(true, true, NULL, name_only, details_flag, 569 + pmu_name); 570 + 571 + print_libpfm_events(name_only, long_desc); 572 + }
+22
tools/perf/util/print-events.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __PERF_PRINT_EVENTS_H 3 + #define __PERF_PRINT_EVENTS_H 4 + 5 + #include <stdbool.h> 6 + 7 + struct event_symbol; 8 + 9 + void print_events(const char *event_glob, bool name_only, bool quiet_flag, 10 + bool long_desc, bool details_flag, bool deprecated, 11 + const char *pmu_name); 12 + int print_hwcache_events(const char *event_glob, bool name_only); 13 + void print_sdt_events(const char *subsys_glob, const char *event_glob, 14 + bool name_only); 15 + void print_symbol_events(const char *event_glob, unsigned int type, 16 + struct event_symbol *syms, unsigned int max, 17 + bool name_only); 18 + void print_tool_events(const char *event_glob, bool name_only); 19 + void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 20 + bool name_only); 21 + 22 + #endif /* __PERF_PRINT_EVENTS_H */
+96
tools/perf/util/trace-event-info.c
··· 19 19 #include <linux/kernel.h> 20 20 #include <linux/zalloc.h> 21 21 #include <internal/lib.h> // page_size 22 + #include <sys/param.h> 22 23 23 24 #include "trace-event.h" 25 + #include "tracepoint.h" 24 26 #include <api/fs/tracing_path.h> 25 27 #include "evsel.h" 26 28 #include "debug.h" 27 29 28 30 #define VERSION "0.6" 31 + #define MAX_EVENT_LENGTH 512 29 32 30 33 static int output_fd; 31 34 35 + struct tracepoint_path { 36 + char *system; 37 + char *name; 38 + struct tracepoint_path *next; 39 + }; 32 40 33 41 int bigendian(void) 34 42 { ··· 406 398 zfree(&t->system); 407 399 free(t); 408 400 } 401 + } 402 + 403 + static struct tracepoint_path *tracepoint_id_to_path(u64 config) 404 + { 405 + struct tracepoint_path *path = NULL; 406 + DIR *sys_dir, *evt_dir; 407 + struct dirent *sys_dirent, *evt_dirent; 408 + char id_buf[24]; 409 + int fd; 410 + u64 id; 411 + char evt_path[MAXPATHLEN]; 412 + char *dir_path; 413 + 414 + sys_dir = tracing_events__opendir(); 415 + if (!sys_dir) 416 + return NULL; 417 + 418 + for_each_subsystem(sys_dir, sys_dirent) { 419 + dir_path = get_events_file(sys_dirent->d_name); 420 + if (!dir_path) 421 + continue; 422 + evt_dir = opendir(dir_path); 423 + if (!evt_dir) 424 + goto next; 425 + 426 + for_each_event(dir_path, evt_dir, evt_dirent) { 427 + 428 + scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, 429 + evt_dirent->d_name); 430 + fd = open(evt_path, O_RDONLY); 431 + if (fd < 0) 432 + continue; 433 + if (read(fd, id_buf, sizeof(id_buf)) < 0) { 434 + close(fd); 435 + continue; 436 + } 437 + close(fd); 438 + id = atoll(id_buf); 439 + if (id == config) { 440 + put_events_file(dir_path); 441 + closedir(evt_dir); 442 + closedir(sys_dir); 443 + path = zalloc(sizeof(*path)); 444 + if (!path) 445 + return NULL; 446 + if (asprintf(&path->system, "%.*s", 447 + MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) { 448 + free(path); 449 + return NULL; 450 + } 451 + if (asprintf(&path->name, "%.*s", 452 + MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) { 453 + zfree(&path->system); 454 + free(path); 455 + return NULL; 456 + } 457 + return path; 458 + } 459 + } 460 + closedir(evt_dir); 461 + next: 462 + put_events_file(dir_path); 463 + } 464 + 465 + closedir(sys_dir); 466 + return NULL; 467 + } 468 + 469 + static struct tracepoint_path *tracepoint_name_to_path(const char *name) 470 + { 471 + struct tracepoint_path *path = zalloc(sizeof(*path)); 472 + char *str = strchr(name, ':'); 473 + 474 + if (path == NULL || str == NULL) { 475 + free(path); 476 + return NULL; 477 + } 478 + 479 + path->system = strndup(name, str - name); 480 + path->name = strdup(str+1); 481 + 482 + if (path->system == NULL || path->name == NULL) { 483 + zfree(&path->system); 484 + zfree(&path->name); 485 + zfree(&path); 486 + } 487 + 488 + return path; 409 489 } 410 490 411 491 static struct tracepoint_path *
+63
tools/perf/util/tracepoint.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include "tracepoint.h" 3 + 4 + #include <errno.h> 5 + #include <fcntl.h> 6 + #include <stdio.h> 7 + #include <sys/param.h> 8 + #include <unistd.h> 9 + 10 + #include <api/fs/tracing_path.h> 11 + 12 + int tp_event_has_id(const char *dir_path, struct dirent *evt_dir) 13 + { 14 + char evt_path[MAXPATHLEN]; 15 + int fd; 16 + 17 + snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name); 18 + fd = open(evt_path, O_RDONLY); 19 + if (fd < 0) 20 + return -EINVAL; 21 + close(fd); 22 + 23 + return 0; 24 + } 25 + 26 + /* 27 + * Check whether event is in <debugfs_mount_point>/tracing/events 28 + */ 29 + int is_valid_tracepoint(const char *event_string) 30 + { 31 + DIR *sys_dir, *evt_dir; 32 + struct dirent *sys_dirent, *evt_dirent; 33 + char evt_path[MAXPATHLEN]; 34 + char *dir_path; 35 + 36 + sys_dir = tracing_events__opendir(); 37 + if (!sys_dir) 38 + return 0; 39 + 40 + for_each_subsystem(sys_dir, sys_dirent) { 41 + dir_path = get_events_file(sys_dirent->d_name); 42 + if (!dir_path) 43 + continue; 44 + evt_dir = opendir(dir_path); 45 + if (!evt_dir) 46 + goto next; 47 + 48 + for_each_event(dir_path, evt_dir, evt_dirent) { 49 + snprintf(evt_path, MAXPATHLEN, "%s:%s", 50 + sys_dirent->d_name, evt_dirent->d_name); 51 + if (!strcmp(evt_path, event_string)) { 52 + closedir(evt_dir); 53 + closedir(sys_dir); 54 + return 1; 55 + } 56 + } 57 + closedir(evt_dir); 58 + next: 59 + put_events_file(dir_path); 60 + } 61 + closedir(sys_dir); 62 + return 0; 63 + }
+25
tools/perf/util/tracepoint.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __PERF_TRACEPOINT_H 3 + #define __PERF_TRACEPOINT_H 4 + 5 + #include <dirent.h> 6 + #include <string.h> 7 + 8 + int tp_event_has_id(const char *dir_path, struct dirent *evt_dir); 9 + 10 + #define for_each_event(dir_path, evt_dir, evt_dirent) \ 11 + while ((evt_dirent = readdir(evt_dir)) != NULL) \ 12 + if (evt_dirent->d_type == DT_DIR && \ 13 + (strcmp(evt_dirent->d_name, ".")) && \ 14 + (strcmp(evt_dirent->d_name, "..")) && \ 15 + (!tp_event_has_id(dir_path, evt_dirent))) 16 + 17 + #define for_each_subsystem(sys_dir, sys_dirent) \ 18 + while ((sys_dirent = readdir(sys_dir)) != NULL) \ 19 + if (sys_dirent->d_type == DT_DIR && \ 20 + (strcmp(sys_dirent->d_name, ".")) && \ 21 + (strcmp(sys_dirent->d_name, ".."))) 22 + 23 + int is_valid_tracepoint(const char *event_string); 24 + 25 + #endif /* __PERF_TRACEPOINT_H */