18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/hw_breakpoint.h> 38c2ecf20Sopenharmony_ci#include <linux/err.h> 48c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 58c2ecf20Sopenharmony_ci#include <dirent.h> 68c2ecf20Sopenharmony_ci#include <errno.h> 78c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 88c2ecf20Sopenharmony_ci#include <sys/types.h> 98c2ecf20Sopenharmony_ci#include <sys/stat.h> 108c2ecf20Sopenharmony_ci#include <fcntl.h> 118c2ecf20Sopenharmony_ci#include <sys/param.h> 128c2ecf20Sopenharmony_ci#include "term.h" 138c2ecf20Sopenharmony_ci#include "build-id.h" 148c2ecf20Sopenharmony_ci#include "evlist.h" 158c2ecf20Sopenharmony_ci#include "evsel.h" 168c2ecf20Sopenharmony_ci#include <subcmd/pager.h> 178c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 188c2ecf20Sopenharmony_ci#include "parse-events.h" 198c2ecf20Sopenharmony_ci#include <subcmd/exec-cmd.h> 208c2ecf20Sopenharmony_ci#include "string2.h" 218c2ecf20Sopenharmony_ci#include "strlist.h" 228c2ecf20Sopenharmony_ci#include "symbol.h" 238c2ecf20Sopenharmony_ci#include "header.h" 248c2ecf20Sopenharmony_ci#include "bpf-loader.h" 258c2ecf20Sopenharmony_ci#include "debug.h" 268c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h> 278c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 288c2ecf20Sopenharmony_ci#include "parse-events-bison.h" 298c2ecf20Sopenharmony_ci#define YY_EXTRA_TYPE void* 308c2ecf20Sopenharmony_ci#include "parse-events-flex.h" 318c2ecf20Sopenharmony_ci#include "pmu.h" 328c2ecf20Sopenharmony_ci#include "thread_map.h" 338c2ecf20Sopenharmony_ci#include "probe-file.h" 348c2ecf20Sopenharmony_ci#include "asm/bug.h" 358c2ecf20Sopenharmony_ci#include "util/parse-branch-options.h" 368c2ecf20Sopenharmony_ci#include "metricgroup.h" 378c2ecf20Sopenharmony_ci#include "util/evsel_config.h" 388c2ecf20Sopenharmony_ci#include "util/event.h" 398c2ecf20Sopenharmony_ci#include "util/pfm.h" 408c2ecf20Sopenharmony_ci#include "perf.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define MAX_NAME_LEN 100 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#ifdef PARSER_DEBUG 458c2ecf20Sopenharmony_ciextern int parse_events_debug; 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ciint parse_events_parse(void *parse_state, void *scanner); 488c2ecf20Sopenharmony_cistatic int get_config_terms(struct list_head *head_config, 498c2ecf20Sopenharmony_ci struct list_head *head_terms __maybe_unused); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic struct perf_pmu_event_symbol *perf_pmu_events_list; 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * The variable indicates the number of supported pmu event symbols. 548c2ecf20Sopenharmony_ci * 0 means not initialized and ready to init 558c2ecf20Sopenharmony_ci * -1 means failed to init, don't try anymore 568c2ecf20Sopenharmony_ci * >0 is the number of supported pmu event symbols 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic int perf_pmu_events_list_num; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { 618c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CPU_CYCLES] = { 628c2ecf20Sopenharmony_ci .symbol = "cpu-cycles", 638c2ecf20Sopenharmony_ci .alias = "cycles", 648c2ecf20Sopenharmony_ci }, 658c2ecf20Sopenharmony_ci [PERF_COUNT_HW_INSTRUCTIONS] = { 668c2ecf20Sopenharmony_ci .symbol = "instructions", 678c2ecf20Sopenharmony_ci .alias = "", 688c2ecf20Sopenharmony_ci }, 698c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_REFERENCES] = { 708c2ecf20Sopenharmony_ci .symbol = "cache-references", 718c2ecf20Sopenharmony_ci .alias = "", 728c2ecf20Sopenharmony_ci }, 738c2ecf20Sopenharmony_ci [PERF_COUNT_HW_CACHE_MISSES] = { 748c2ecf20Sopenharmony_ci .symbol = "cache-misses", 758c2ecf20Sopenharmony_ci .alias = "", 768c2ecf20Sopenharmony_ci }, 778c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 788c2ecf20Sopenharmony_ci .symbol = "branch-instructions", 798c2ecf20Sopenharmony_ci .alias = "branches", 808c2ecf20Sopenharmony_ci }, 818c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BRANCH_MISSES] = { 828c2ecf20Sopenharmony_ci .symbol = "branch-misses", 838c2ecf20Sopenharmony_ci .alias = "", 848c2ecf20Sopenharmony_ci }, 858c2ecf20Sopenharmony_ci [PERF_COUNT_HW_BUS_CYCLES] = { 868c2ecf20Sopenharmony_ci .symbol = "bus-cycles", 878c2ecf20Sopenharmony_ci .alias = "", 888c2ecf20Sopenharmony_ci }, 898c2ecf20Sopenharmony_ci [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = { 908c2ecf20Sopenharmony_ci .symbol = "stalled-cycles-frontend", 918c2ecf20Sopenharmony_ci .alias = "idle-cycles-frontend", 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = { 948c2ecf20Sopenharmony_ci .symbol = "stalled-cycles-backend", 958c2ecf20Sopenharmony_ci .alias = "idle-cycles-backend", 968c2ecf20Sopenharmony_ci }, 978c2ecf20Sopenharmony_ci [PERF_COUNT_HW_REF_CPU_CYCLES] = { 988c2ecf20Sopenharmony_ci .symbol = "ref-cycles", 998c2ecf20Sopenharmony_ci .alias = "", 1008c2ecf20Sopenharmony_ci }, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { 1048c2ecf20Sopenharmony_ci [PERF_COUNT_SW_CPU_CLOCK] = { 1058c2ecf20Sopenharmony_ci .symbol = "cpu-clock", 1068c2ecf20Sopenharmony_ci .alias = "", 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci [PERF_COUNT_SW_TASK_CLOCK] = { 1098c2ecf20Sopenharmony_ci .symbol = "task-clock", 1108c2ecf20Sopenharmony_ci .alias = "", 1118c2ecf20Sopenharmony_ci }, 1128c2ecf20Sopenharmony_ci [PERF_COUNT_SW_PAGE_FAULTS] = { 1138c2ecf20Sopenharmony_ci .symbol = "page-faults", 1148c2ecf20Sopenharmony_ci .alias = "faults", 1158c2ecf20Sopenharmony_ci }, 1168c2ecf20Sopenharmony_ci [PERF_COUNT_SW_CONTEXT_SWITCHES] = { 1178c2ecf20Sopenharmony_ci .symbol = "context-switches", 1188c2ecf20Sopenharmony_ci .alias = "cs", 1198c2ecf20Sopenharmony_ci }, 1208c2ecf20Sopenharmony_ci [PERF_COUNT_SW_CPU_MIGRATIONS] = { 1218c2ecf20Sopenharmony_ci .symbol = "cpu-migrations", 1228c2ecf20Sopenharmony_ci .alias = "migrations", 1238c2ecf20Sopenharmony_ci }, 1248c2ecf20Sopenharmony_ci [PERF_COUNT_SW_PAGE_FAULTS_MIN] = { 1258c2ecf20Sopenharmony_ci .symbol = "minor-faults", 1268c2ecf20Sopenharmony_ci .alias = "", 1278c2ecf20Sopenharmony_ci }, 1288c2ecf20Sopenharmony_ci [PERF_COUNT_SW_PAGE_FAULTS_MAJ] = { 1298c2ecf20Sopenharmony_ci .symbol = "major-faults", 1308c2ecf20Sopenharmony_ci .alias = "", 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci [PERF_COUNT_SW_ALIGNMENT_FAULTS] = { 1338c2ecf20Sopenharmony_ci .symbol = "alignment-faults", 1348c2ecf20Sopenharmony_ci .alias = "", 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci [PERF_COUNT_SW_EMULATION_FAULTS] = { 1378c2ecf20Sopenharmony_ci .symbol = "emulation-faults", 1388c2ecf20Sopenharmony_ci .alias = "", 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci [PERF_COUNT_SW_DUMMY] = { 1418c2ecf20Sopenharmony_ci .symbol = "dummy", 1428c2ecf20Sopenharmony_ci .alias = "", 1438c2ecf20Sopenharmony_ci }, 1448c2ecf20Sopenharmony_ci [PERF_COUNT_SW_BPF_OUTPUT] = { 1458c2ecf20Sopenharmony_ci .symbol = "bpf-output", 1468c2ecf20Sopenharmony_ci .alias = "", 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define __PERF_EVENT_FIELD(config, name) \ 1518c2ecf20Sopenharmony_ci ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW) 1548c2ecf20Sopenharmony_ci#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG) 1558c2ecf20Sopenharmony_ci#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 1568c2ecf20Sopenharmony_ci#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define for_each_subsystem(sys_dir, sys_dirent) \ 1598c2ecf20Sopenharmony_ci while ((sys_dirent = readdir(sys_dir)) != NULL) \ 1608c2ecf20Sopenharmony_ci if (sys_dirent->d_type == DT_DIR && \ 1618c2ecf20Sopenharmony_ci (strcmp(sys_dirent->d_name, ".")) && \ 1628c2ecf20Sopenharmony_ci (strcmp(sys_dirent->d_name, ".."))) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int tp_event_has_id(const char *dir_path, struct dirent *evt_dir) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci char evt_path[MAXPATHLEN]; 1678c2ecf20Sopenharmony_ci int fd; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name); 1708c2ecf20Sopenharmony_ci fd = open(evt_path, O_RDONLY); 1718c2ecf20Sopenharmony_ci if (fd < 0) 1728c2ecf20Sopenharmony_ci return -EINVAL; 1738c2ecf20Sopenharmony_ci close(fd); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define for_each_event(dir_path, evt_dir, evt_dirent) \ 1798c2ecf20Sopenharmony_ci while ((evt_dirent = readdir(evt_dir)) != NULL) \ 1808c2ecf20Sopenharmony_ci if (evt_dirent->d_type == DT_DIR && \ 1818c2ecf20Sopenharmony_ci (strcmp(evt_dirent->d_name, ".")) && \ 1828c2ecf20Sopenharmony_ci (strcmp(evt_dirent->d_name, "..")) && \ 1838c2ecf20Sopenharmony_ci (!tp_event_has_id(dir_path, evt_dirent))) 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#define MAX_EVENT_LENGTH 512 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_civoid parse_events__handle_error(struct parse_events_error *err, int idx, 1888c2ecf20Sopenharmony_ci char *str, char *help) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci if (WARN(!str, "WARNING: failed to provide error string\n")) { 1918c2ecf20Sopenharmony_ci free(help); 1928c2ecf20Sopenharmony_ci return; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci switch (err->num_errors) { 1958c2ecf20Sopenharmony_ci case 0: 1968c2ecf20Sopenharmony_ci err->idx = idx; 1978c2ecf20Sopenharmony_ci err->str = str; 1988c2ecf20Sopenharmony_ci err->help = help; 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci case 1: 2018c2ecf20Sopenharmony_ci err->first_idx = err->idx; 2028c2ecf20Sopenharmony_ci err->idx = idx; 2038c2ecf20Sopenharmony_ci err->first_str = err->str; 2048c2ecf20Sopenharmony_ci err->str = str; 2058c2ecf20Sopenharmony_ci err->first_help = err->help; 2068c2ecf20Sopenharmony_ci err->help = help; 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci default: 2098c2ecf20Sopenharmony_ci pr_debug("Multiple errors dropping message: %s (%s)\n", 2108c2ecf20Sopenharmony_ci err->str, err->help); 2118c2ecf20Sopenharmony_ci free(err->str); 2128c2ecf20Sopenharmony_ci err->str = str; 2138c2ecf20Sopenharmony_ci free(err->help); 2148c2ecf20Sopenharmony_ci err->help = help; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci err->num_errors++; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistruct tracepoint_path *tracepoint_id_to_path(u64 config) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct tracepoint_path *path = NULL; 2238c2ecf20Sopenharmony_ci DIR *sys_dir, *evt_dir; 2248c2ecf20Sopenharmony_ci struct dirent *sys_dirent, *evt_dirent; 2258c2ecf20Sopenharmony_ci char id_buf[24]; 2268c2ecf20Sopenharmony_ci int fd; 2278c2ecf20Sopenharmony_ci u64 id; 2288c2ecf20Sopenharmony_ci char evt_path[MAXPATHLEN]; 2298c2ecf20Sopenharmony_ci char *dir_path; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci sys_dir = tracing_events__opendir(); 2328c2ecf20Sopenharmony_ci if (!sys_dir) 2338c2ecf20Sopenharmony_ci return NULL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci for_each_subsystem(sys_dir, sys_dirent) { 2368c2ecf20Sopenharmony_ci dir_path = get_events_file(sys_dirent->d_name); 2378c2ecf20Sopenharmony_ci if (!dir_path) 2388c2ecf20Sopenharmony_ci continue; 2398c2ecf20Sopenharmony_ci evt_dir = opendir(dir_path); 2408c2ecf20Sopenharmony_ci if (!evt_dir) 2418c2ecf20Sopenharmony_ci goto next; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci for_each_event(dir_path, evt_dir, evt_dirent) { 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, 2468c2ecf20Sopenharmony_ci evt_dirent->d_name); 2478c2ecf20Sopenharmony_ci fd = open(evt_path, O_RDONLY); 2488c2ecf20Sopenharmony_ci if (fd < 0) 2498c2ecf20Sopenharmony_ci continue; 2508c2ecf20Sopenharmony_ci if (read(fd, id_buf, sizeof(id_buf)) < 0) { 2518c2ecf20Sopenharmony_ci close(fd); 2528c2ecf20Sopenharmony_ci continue; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci close(fd); 2558c2ecf20Sopenharmony_ci id = atoll(id_buf); 2568c2ecf20Sopenharmony_ci if (id == config) { 2578c2ecf20Sopenharmony_ci put_events_file(dir_path); 2588c2ecf20Sopenharmony_ci closedir(evt_dir); 2598c2ecf20Sopenharmony_ci closedir(sys_dir); 2608c2ecf20Sopenharmony_ci path = zalloc(sizeof(*path)); 2618c2ecf20Sopenharmony_ci if (!path) 2628c2ecf20Sopenharmony_ci return NULL; 2638c2ecf20Sopenharmony_ci if (asprintf(&path->system, "%.*s", MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) { 2648c2ecf20Sopenharmony_ci free(path); 2658c2ecf20Sopenharmony_ci return NULL; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci if (asprintf(&path->name, "%.*s", MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) { 2688c2ecf20Sopenharmony_ci zfree(&path->system); 2698c2ecf20Sopenharmony_ci free(path); 2708c2ecf20Sopenharmony_ci return NULL; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci return path; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci closedir(evt_dir); 2768c2ecf20Sopenharmony_cinext: 2778c2ecf20Sopenharmony_ci put_events_file(dir_path); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci closedir(sys_dir); 2818c2ecf20Sopenharmony_ci return NULL; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistruct tracepoint_path *tracepoint_name_to_path(const char *name) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct tracepoint_path *path = zalloc(sizeof(*path)); 2878c2ecf20Sopenharmony_ci char *str = strchr(name, ':'); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (path == NULL || str == NULL) { 2908c2ecf20Sopenharmony_ci free(path); 2918c2ecf20Sopenharmony_ci return NULL; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci path->system = strndup(name, str - name); 2958c2ecf20Sopenharmony_ci path->name = strdup(str+1); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (path->system == NULL || path->name == NULL) { 2988c2ecf20Sopenharmony_ci zfree(&path->system); 2998c2ecf20Sopenharmony_ci zfree(&path->name); 3008c2ecf20Sopenharmony_ci zfree(&path); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return path; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciconst char *event_type(int type) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci switch (type) { 3098c2ecf20Sopenharmony_ci case PERF_TYPE_HARDWARE: 3108c2ecf20Sopenharmony_ci return "hardware"; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci case PERF_TYPE_SOFTWARE: 3138c2ecf20Sopenharmony_ci return "software"; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci case PERF_TYPE_TRACEPOINT: 3168c2ecf20Sopenharmony_ci return "tracepoint"; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci case PERF_TYPE_HW_CACHE: 3198c2ecf20Sopenharmony_ci return "hardware-cache"; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci default: 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return "unknown"; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int parse_events__is_name_term(struct parse_events_term *term) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic char *get_config_name(struct list_head *head_terms) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct parse_events_term *term; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!head_terms) 3388c2ecf20Sopenharmony_ci return NULL; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci list_for_each_entry(term, head_terms, list) 3418c2ecf20Sopenharmony_ci if (parse_events__is_name_term(term)) 3428c2ecf20Sopenharmony_ci return term->val.str; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return NULL; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic struct evsel * 3488c2ecf20Sopenharmony_ci__add_event(struct list_head *list, int *idx, 3498c2ecf20Sopenharmony_ci struct perf_event_attr *attr, 3508c2ecf20Sopenharmony_ci bool init_attr, 3518c2ecf20Sopenharmony_ci char *name, struct perf_pmu *pmu, 3528c2ecf20Sopenharmony_ci struct list_head *config_terms, bool auto_merge_stats, 3538c2ecf20Sopenharmony_ci const char *cpu_list) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct evsel *evsel; 3568c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus = pmu ? perf_cpu_map__get(pmu->cpus) : 3578c2ecf20Sopenharmony_ci cpu_list ? perf_cpu_map__new(cpu_list) : NULL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (pmu) 3608c2ecf20Sopenharmony_ci perf_pmu__warn_invalid_formats(pmu); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (pmu && attr->type == PERF_TYPE_RAW) 3638c2ecf20Sopenharmony_ci perf_pmu__warn_invalid_config(pmu, attr->config, name); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (init_attr) 3668c2ecf20Sopenharmony_ci event_attr_init(attr); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci evsel = evsel__new_idx(attr, *idx); 3698c2ecf20Sopenharmony_ci if (!evsel) { 3708c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 3718c2ecf20Sopenharmony_ci return NULL; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci (*idx)++; 3758c2ecf20Sopenharmony_ci evsel->core.cpus = cpus; 3768c2ecf20Sopenharmony_ci evsel->core.own_cpus = perf_cpu_map__get(cpus); 3778c2ecf20Sopenharmony_ci evsel->core.system_wide = pmu ? pmu->is_uncore : false; 3788c2ecf20Sopenharmony_ci evsel->auto_merge_stats = auto_merge_stats; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (name) 3818c2ecf20Sopenharmony_ci evsel->name = strdup(name); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (config_terms) 3848c2ecf20Sopenharmony_ci list_splice(config_terms, &evsel->config_terms); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (list) 3878c2ecf20Sopenharmony_ci list_add_tail(&evsel->core.node, list); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return evsel; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistruct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, 3938c2ecf20Sopenharmony_ci char *name, struct perf_pmu *pmu) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci return __add_event(NULL, &idx, attr, false, name, pmu, NULL, false, 3968c2ecf20Sopenharmony_ci NULL); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int add_event(struct list_head *list, int *idx, 4008c2ecf20Sopenharmony_ci struct perf_event_attr *attr, char *name, 4018c2ecf20Sopenharmony_ci struct list_head *config_terms) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci return __add_event(list, idx, attr, true, name, NULL, config_terms, 4048c2ecf20Sopenharmony_ci false, NULL) ? 0 : -ENOMEM; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic int add_event_tool(struct list_head *list, int *idx, 4088c2ecf20Sopenharmony_ci enum perf_tool_event tool_event) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct evsel *evsel; 4118c2ecf20Sopenharmony_ci struct perf_event_attr attr = { 4128c2ecf20Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 4138c2ecf20Sopenharmony_ci .config = PERF_COUNT_SW_DUMMY, 4148c2ecf20Sopenharmony_ci }; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci evsel = __add_event(list, idx, &attr, true, NULL, NULL, NULL, false, 4178c2ecf20Sopenharmony_ci "0"); 4188c2ecf20Sopenharmony_ci if (!evsel) 4198c2ecf20Sopenharmony_ci return -ENOMEM; 4208c2ecf20Sopenharmony_ci evsel->tool_event = tool_event; 4218c2ecf20Sopenharmony_ci if (tool_event == PERF_TOOL_DURATION_TIME) 4228c2ecf20Sopenharmony_ci evsel->unit = "ns"; 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int parse_aliases(char *str, const char *names[][EVSEL__MAX_ALIASES], int size) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci int i, j; 4298c2ecf20Sopenharmony_ci int n, longest = -1; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) { 4328c2ecf20Sopenharmony_ci for (j = 0; j < EVSEL__MAX_ALIASES && names[i][j]; j++) { 4338c2ecf20Sopenharmony_ci n = strlen(names[i][j]); 4348c2ecf20Sopenharmony_ci if (n > longest && !strncasecmp(str, names[i][j], n)) 4358c2ecf20Sopenharmony_ci longest = n; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci if (longest > 0) 4388c2ecf20Sopenharmony_ci return i; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return -1; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_citypedef int config_term_func_t(struct perf_event_attr *attr, 4458c2ecf20Sopenharmony_ci struct parse_events_term *term, 4468c2ecf20Sopenharmony_ci struct parse_events_error *err); 4478c2ecf20Sopenharmony_cistatic int config_term_common(struct perf_event_attr *attr, 4488c2ecf20Sopenharmony_ci struct parse_events_term *term, 4498c2ecf20Sopenharmony_ci struct parse_events_error *err); 4508c2ecf20Sopenharmony_cistatic int config_attr(struct perf_event_attr *attr, 4518c2ecf20Sopenharmony_ci struct list_head *head, 4528c2ecf20Sopenharmony_ci struct parse_events_error *err, 4538c2ecf20Sopenharmony_ci config_term_func_t config_term); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ciint parse_events_add_cache(struct list_head *list, int *idx, 4568c2ecf20Sopenharmony_ci char *type, char *op_result1, char *op_result2, 4578c2ecf20Sopenharmony_ci struct parse_events_error *err, 4588c2ecf20Sopenharmony_ci struct list_head *head_config) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct perf_event_attr attr; 4618c2ecf20Sopenharmony_ci LIST_HEAD(config_terms); 4628c2ecf20Sopenharmony_ci char name[MAX_NAME_LEN], *config_name; 4638c2ecf20Sopenharmony_ci int cache_type = -1, cache_op = -1, cache_result = -1; 4648c2ecf20Sopenharmony_ci char *op_result[2] = { op_result1, op_result2 }; 4658c2ecf20Sopenharmony_ci int i, n; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* 4688c2ecf20Sopenharmony_ci * No fallback - if we cannot get a clear cache type 4698c2ecf20Sopenharmony_ci * then bail out: 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci cache_type = parse_aliases(type, evsel__hw_cache, PERF_COUNT_HW_CACHE_MAX); 4728c2ecf20Sopenharmony_ci if (cache_type == -1) 4738c2ecf20Sopenharmony_ci return -EINVAL; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci config_name = get_config_name(head_config); 4768c2ecf20Sopenharmony_ci n = snprintf(name, MAX_NAME_LEN, "%s", type); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci for (i = 0; (i < 2) && (op_result[i]); i++) { 4798c2ecf20Sopenharmony_ci char *str = op_result[i]; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (cache_op == -1) { 4848c2ecf20Sopenharmony_ci cache_op = parse_aliases(str, evsel__hw_cache_op, 4858c2ecf20Sopenharmony_ci PERF_COUNT_HW_CACHE_OP_MAX); 4868c2ecf20Sopenharmony_ci if (cache_op >= 0) { 4878c2ecf20Sopenharmony_ci if (!evsel__is_cache_op_valid(cache_type, cache_op)) 4888c2ecf20Sopenharmony_ci return -EINVAL; 4898c2ecf20Sopenharmony_ci continue; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (cache_result == -1) { 4948c2ecf20Sopenharmony_ci cache_result = parse_aliases(str, evsel__hw_cache_result, 4958c2ecf20Sopenharmony_ci PERF_COUNT_HW_CACHE_RESULT_MAX); 4968c2ecf20Sopenharmony_ci if (cache_result >= 0) 4978c2ecf20Sopenharmony_ci continue; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* 5028c2ecf20Sopenharmony_ci * Fall back to reads: 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci if (cache_op == -1) 5058c2ecf20Sopenharmony_ci cache_op = PERF_COUNT_HW_CACHE_OP_READ; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * Fall back to accesses: 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_ci if (cache_result == -1) 5118c2ecf20Sopenharmony_ci cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 5148c2ecf20Sopenharmony_ci attr.config = cache_type | (cache_op << 8) | (cache_result << 16); 5158c2ecf20Sopenharmony_ci attr.type = PERF_TYPE_HW_CACHE; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (head_config) { 5188c2ecf20Sopenharmony_ci if (config_attr(&attr, head_config, err, 5198c2ecf20Sopenharmony_ci config_term_common)) 5208c2ecf20Sopenharmony_ci return -EINVAL; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (get_config_terms(head_config, &config_terms)) 5238c2ecf20Sopenharmony_ci return -ENOMEM; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci return add_event(list, idx, &attr, config_name ? : name, &config_terms); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic void tracepoint_error(struct parse_events_error *e, int err, 5298c2ecf20Sopenharmony_ci const char *sys, const char *name) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci const char *str; 5328c2ecf20Sopenharmony_ci char help[BUFSIZ]; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!e) 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * We get error directly from syscall errno ( > 0), 5398c2ecf20Sopenharmony_ci * or from encoded pointer's error ( < 0). 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ci err = abs(err); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci switch (err) { 5448c2ecf20Sopenharmony_ci case EACCES: 5458c2ecf20Sopenharmony_ci str = "can't access trace events"; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case ENOENT: 5488c2ecf20Sopenharmony_ci str = "unknown tracepoint"; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci default: 5518c2ecf20Sopenharmony_ci str = "failed to add tracepoint"; 5528c2ecf20Sopenharmony_ci break; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); 5568c2ecf20Sopenharmony_ci parse_events__handle_error(e, 0, strdup(str), strdup(help)); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int add_tracepoint(struct list_head *list, int *idx, 5608c2ecf20Sopenharmony_ci const char *sys_name, const char *evt_name, 5618c2ecf20Sopenharmony_ci struct parse_events_error *err, 5628c2ecf20Sopenharmony_ci struct list_head *head_config) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct evsel *evsel = evsel__newtp_idx(sys_name, evt_name, (*idx)++); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (IS_ERR(evsel)) { 5678c2ecf20Sopenharmony_ci tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name); 5688c2ecf20Sopenharmony_ci return PTR_ERR(evsel); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (head_config) { 5728c2ecf20Sopenharmony_ci LIST_HEAD(config_terms); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (get_config_terms(head_config, &config_terms)) 5758c2ecf20Sopenharmony_ci return -ENOMEM; 5768c2ecf20Sopenharmony_ci list_splice(&config_terms, &evsel->config_terms); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci list_add_tail(&evsel->core.node, list); 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int add_tracepoint_multi_event(struct list_head *list, int *idx, 5848c2ecf20Sopenharmony_ci const char *sys_name, const char *evt_name, 5858c2ecf20Sopenharmony_ci struct parse_events_error *err, 5868c2ecf20Sopenharmony_ci struct list_head *head_config) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci char *evt_path; 5898c2ecf20Sopenharmony_ci struct dirent *evt_ent; 5908c2ecf20Sopenharmony_ci DIR *evt_dir; 5918c2ecf20Sopenharmony_ci int ret = 0, found = 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci evt_path = get_events_file(sys_name); 5948c2ecf20Sopenharmony_ci if (!evt_path) { 5958c2ecf20Sopenharmony_ci tracepoint_error(err, errno, sys_name, evt_name); 5968c2ecf20Sopenharmony_ci return -1; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci evt_dir = opendir(evt_path); 5998c2ecf20Sopenharmony_ci if (!evt_dir) { 6008c2ecf20Sopenharmony_ci put_events_file(evt_path); 6018c2ecf20Sopenharmony_ci tracepoint_error(err, errno, sys_name, evt_name); 6028c2ecf20Sopenharmony_ci return -1; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci while (!ret && (evt_ent = readdir(evt_dir))) { 6068c2ecf20Sopenharmony_ci if (!strcmp(evt_ent->d_name, ".") 6078c2ecf20Sopenharmony_ci || !strcmp(evt_ent->d_name, "..") 6088c2ecf20Sopenharmony_ci || !strcmp(evt_ent->d_name, "enable") 6098c2ecf20Sopenharmony_ci || !strcmp(evt_ent->d_name, "filter")) 6108c2ecf20Sopenharmony_ci continue; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (!strglobmatch(evt_ent->d_name, evt_name)) 6138c2ecf20Sopenharmony_ci continue; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci found++; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, 6188c2ecf20Sopenharmony_ci err, head_config); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (!found) { 6228c2ecf20Sopenharmony_ci tracepoint_error(err, ENOENT, sys_name, evt_name); 6238c2ecf20Sopenharmony_ci ret = -1; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci put_events_file(evt_path); 6278c2ecf20Sopenharmony_ci closedir(evt_dir); 6288c2ecf20Sopenharmony_ci return ret; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic int add_tracepoint_event(struct list_head *list, int *idx, 6328c2ecf20Sopenharmony_ci const char *sys_name, const char *evt_name, 6338c2ecf20Sopenharmony_ci struct parse_events_error *err, 6348c2ecf20Sopenharmony_ci struct list_head *head_config) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci return strpbrk(evt_name, "*?") ? 6378c2ecf20Sopenharmony_ci add_tracepoint_multi_event(list, idx, sys_name, evt_name, 6388c2ecf20Sopenharmony_ci err, head_config) : 6398c2ecf20Sopenharmony_ci add_tracepoint(list, idx, sys_name, evt_name, 6408c2ecf20Sopenharmony_ci err, head_config); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int add_tracepoint_multi_sys(struct list_head *list, int *idx, 6448c2ecf20Sopenharmony_ci const char *sys_name, const char *evt_name, 6458c2ecf20Sopenharmony_ci struct parse_events_error *err, 6468c2ecf20Sopenharmony_ci struct list_head *head_config) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct dirent *events_ent; 6498c2ecf20Sopenharmony_ci DIR *events_dir; 6508c2ecf20Sopenharmony_ci int ret = 0; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci events_dir = tracing_events__opendir(); 6538c2ecf20Sopenharmony_ci if (!events_dir) { 6548c2ecf20Sopenharmony_ci tracepoint_error(err, errno, sys_name, evt_name); 6558c2ecf20Sopenharmony_ci return -1; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci while (!ret && (events_ent = readdir(events_dir))) { 6598c2ecf20Sopenharmony_ci if (!strcmp(events_ent->d_name, ".") 6608c2ecf20Sopenharmony_ci || !strcmp(events_ent->d_name, "..") 6618c2ecf20Sopenharmony_ci || !strcmp(events_ent->d_name, "enable") 6628c2ecf20Sopenharmony_ci || !strcmp(events_ent->d_name, "header_event") 6638c2ecf20Sopenharmony_ci || !strcmp(events_ent->d_name, "header_page")) 6648c2ecf20Sopenharmony_ci continue; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!strglobmatch(events_ent->d_name, sys_name)) 6678c2ecf20Sopenharmony_ci continue; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci ret = add_tracepoint_event(list, idx, events_ent->d_name, 6708c2ecf20Sopenharmony_ci evt_name, err, head_config); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci closedir(events_dir); 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistruct __add_bpf_event_param { 6788c2ecf20Sopenharmony_ci struct parse_events_state *parse_state; 6798c2ecf20Sopenharmony_ci struct list_head *list; 6808c2ecf20Sopenharmony_ci struct list_head *head_config; 6818c2ecf20Sopenharmony_ci}; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int add_bpf_event(const char *group, const char *event, int fd, struct bpf_object *obj, 6848c2ecf20Sopenharmony_ci void *_param) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci LIST_HEAD(new_evsels); 6878c2ecf20Sopenharmony_ci struct __add_bpf_event_param *param = _param; 6888c2ecf20Sopenharmony_ci struct parse_events_state *parse_state = param->parse_state; 6898c2ecf20Sopenharmony_ci struct list_head *list = param->list; 6908c2ecf20Sopenharmony_ci struct evsel *pos; 6918c2ecf20Sopenharmony_ci int err; 6928c2ecf20Sopenharmony_ci /* 6938c2ecf20Sopenharmony_ci * Check if we should add the event, i.e. if it is a TP but starts with a '!', 6948c2ecf20Sopenharmony_ci * then don't add the tracepoint, this will be used for something else, like 6958c2ecf20Sopenharmony_ci * adding to a BPF_MAP_TYPE_PROG_ARRAY. 6968c2ecf20Sopenharmony_ci * 6978c2ecf20Sopenharmony_ci * See tools/perf/examples/bpf/augmented_raw_syscalls.c 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci if (group[0] == '!') 7008c2ecf20Sopenharmony_ci return 0; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci pr_debug("add bpf event %s:%s and attach bpf program %d\n", 7038c2ecf20Sopenharmony_ci group, event, fd); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci err = parse_events_add_tracepoint(&new_evsels, &parse_state->idx, group, 7068c2ecf20Sopenharmony_ci event, parse_state->error, 7078c2ecf20Sopenharmony_ci param->head_config); 7088c2ecf20Sopenharmony_ci if (err) { 7098c2ecf20Sopenharmony_ci struct evsel *evsel, *tmp; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci pr_debug("Failed to add BPF event %s:%s\n", 7128c2ecf20Sopenharmony_ci group, event); 7138c2ecf20Sopenharmony_ci list_for_each_entry_safe(evsel, tmp, &new_evsels, core.node) { 7148c2ecf20Sopenharmony_ci list_del_init(&evsel->core.node); 7158c2ecf20Sopenharmony_ci evsel__delete(evsel); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci return err; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci pr_debug("adding %s:%s\n", group, event); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci list_for_each_entry(pos, &new_evsels, core.node) { 7228c2ecf20Sopenharmony_ci pr_debug("adding %s:%s to %p\n", 7238c2ecf20Sopenharmony_ci group, event, pos); 7248c2ecf20Sopenharmony_ci pos->bpf_fd = fd; 7258c2ecf20Sopenharmony_ci pos->bpf_obj = obj; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci list_splice(&new_evsels, list); 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ciint parse_events_load_bpf_obj(struct parse_events_state *parse_state, 7328c2ecf20Sopenharmony_ci struct list_head *list, 7338c2ecf20Sopenharmony_ci struct bpf_object *obj, 7348c2ecf20Sopenharmony_ci struct list_head *head_config) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci int err; 7378c2ecf20Sopenharmony_ci char errbuf[BUFSIZ]; 7388c2ecf20Sopenharmony_ci struct __add_bpf_event_param param = {parse_state, list, head_config}; 7398c2ecf20Sopenharmony_ci static bool registered_unprobe_atexit = false; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (IS_ERR(obj) || !obj) { 7428c2ecf20Sopenharmony_ci snprintf(errbuf, sizeof(errbuf), 7438c2ecf20Sopenharmony_ci "Internal error: load bpf obj with NULL"); 7448c2ecf20Sopenharmony_ci err = -EINVAL; 7458c2ecf20Sopenharmony_ci goto errout; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* 7498c2ecf20Sopenharmony_ci * Register atexit handler before calling bpf__probe() so 7508c2ecf20Sopenharmony_ci * bpf__probe() don't need to unprobe probe points its already 7518c2ecf20Sopenharmony_ci * created when failure. 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci if (!registered_unprobe_atexit) { 7548c2ecf20Sopenharmony_ci atexit(bpf__clear); 7558c2ecf20Sopenharmony_ci registered_unprobe_atexit = true; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci err = bpf__probe(obj); 7598c2ecf20Sopenharmony_ci if (err) { 7608c2ecf20Sopenharmony_ci bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf)); 7618c2ecf20Sopenharmony_ci goto errout; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci err = bpf__load(obj); 7658c2ecf20Sopenharmony_ci if (err) { 7668c2ecf20Sopenharmony_ci bpf__strerror_load(obj, err, errbuf, sizeof(errbuf)); 7678c2ecf20Sopenharmony_ci goto errout; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci err = bpf__foreach_event(obj, add_bpf_event, ¶m); 7718c2ecf20Sopenharmony_ci if (err) { 7728c2ecf20Sopenharmony_ci snprintf(errbuf, sizeof(errbuf), 7738c2ecf20Sopenharmony_ci "Attach events in BPF object failed"); 7748c2ecf20Sopenharmony_ci goto errout; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_cierrout: 7798c2ecf20Sopenharmony_ci parse_events__handle_error(parse_state->error, 0, 7808c2ecf20Sopenharmony_ci strdup(errbuf), strdup("(add -v to see detail)")); 7818c2ecf20Sopenharmony_ci return err; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int 7858c2ecf20Sopenharmony_ciparse_events_config_bpf(struct parse_events_state *parse_state, 7868c2ecf20Sopenharmony_ci struct bpf_object *obj, 7878c2ecf20Sopenharmony_ci struct list_head *head_config) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct parse_events_term *term; 7908c2ecf20Sopenharmony_ci int error_pos; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (!head_config || list_empty(head_config)) 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci list_for_each_entry(term, head_config, list) { 7968c2ecf20Sopenharmony_ci int err; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) { 7998c2ecf20Sopenharmony_ci parse_events__handle_error(parse_state->error, term->err_term, 8008c2ecf20Sopenharmony_ci strdup("Invalid config term for BPF object"), 8018c2ecf20Sopenharmony_ci NULL); 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci err = bpf__config_obj(obj, term, parse_state->evlist, &error_pos); 8068c2ecf20Sopenharmony_ci if (err) { 8078c2ecf20Sopenharmony_ci char errbuf[BUFSIZ]; 8088c2ecf20Sopenharmony_ci int idx; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci bpf__strerror_config_obj(obj, term, parse_state->evlist, 8118c2ecf20Sopenharmony_ci &error_pos, err, errbuf, 8128c2ecf20Sopenharmony_ci sizeof(errbuf)); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE) 8158c2ecf20Sopenharmony_ci idx = term->err_val; 8168c2ecf20Sopenharmony_ci else 8178c2ecf20Sopenharmony_ci idx = term->err_term + error_pos; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci parse_events__handle_error(parse_state->error, idx, 8208c2ecf20Sopenharmony_ci strdup(errbuf), 8218c2ecf20Sopenharmony_ci strdup( 8228c2ecf20Sopenharmony_ci"Hint:\tValid config terms:\n" 8238c2ecf20Sopenharmony_ci" \tmap:[<arraymap>].value<indices>=[value]\n" 8248c2ecf20Sopenharmony_ci" \tmap:[<eventmap>].event<indices>=[event]\n" 8258c2ecf20Sopenharmony_ci"\n" 8268c2ecf20Sopenharmony_ci" \twhere <indices> is something like [0,3...5] or [all]\n" 8278c2ecf20Sopenharmony_ci" \t(add -v to see detail)")); 8288c2ecf20Sopenharmony_ci return err; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/* 8358c2ecf20Sopenharmony_ci * Split config terms: 8368c2ecf20Sopenharmony_ci * perf record -e bpf.c/call-graph=fp,map:array.value[0]=1/ ... 8378c2ecf20Sopenharmony_ci * 'call-graph=fp' is 'evt config', should be applied to each 8388c2ecf20Sopenharmony_ci * events in bpf.c. 8398c2ecf20Sopenharmony_ci * 'map:array.value[0]=1' is 'obj config', should be processed 8408c2ecf20Sopenharmony_ci * with parse_events_config_bpf. 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * Move object config terms from the first list to obj_head_config. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_cistatic void 8458c2ecf20Sopenharmony_cisplit_bpf_config_terms(struct list_head *evt_head_config, 8468c2ecf20Sopenharmony_ci struct list_head *obj_head_config) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct parse_events_term *term, *temp; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* 8518c2ecf20Sopenharmony_ci * Currectly, all possible user config term 8528c2ecf20Sopenharmony_ci * belong to bpf object. parse_events__is_hardcoded_term() 8538c2ecf20Sopenharmony_ci * happends to be a good flag. 8548c2ecf20Sopenharmony_ci * 8558c2ecf20Sopenharmony_ci * See parse_events_config_bpf() and 8568c2ecf20Sopenharmony_ci * config_term_tracepoint(). 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_ci list_for_each_entry_safe(term, temp, evt_head_config, list) 8598c2ecf20Sopenharmony_ci if (!parse_events__is_hardcoded_term(term)) 8608c2ecf20Sopenharmony_ci list_move_tail(&term->list, obj_head_config); 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ciint parse_events_load_bpf(struct parse_events_state *parse_state, 8648c2ecf20Sopenharmony_ci struct list_head *list, 8658c2ecf20Sopenharmony_ci char *bpf_file_name, 8668c2ecf20Sopenharmony_ci bool source, 8678c2ecf20Sopenharmony_ci struct list_head *head_config) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci int err; 8708c2ecf20Sopenharmony_ci struct bpf_object *obj; 8718c2ecf20Sopenharmony_ci LIST_HEAD(obj_head_config); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (head_config) 8748c2ecf20Sopenharmony_ci split_bpf_config_terms(head_config, &obj_head_config); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci obj = bpf__prepare_load(bpf_file_name, source); 8778c2ecf20Sopenharmony_ci if (IS_ERR(obj)) { 8788c2ecf20Sopenharmony_ci char errbuf[BUFSIZ]; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci err = PTR_ERR(obj); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (err == -ENOTSUP) 8838c2ecf20Sopenharmony_ci snprintf(errbuf, sizeof(errbuf), 8848c2ecf20Sopenharmony_ci "BPF support is not compiled"); 8858c2ecf20Sopenharmony_ci else 8868c2ecf20Sopenharmony_ci bpf__strerror_prepare_load(bpf_file_name, 8878c2ecf20Sopenharmony_ci source, 8888c2ecf20Sopenharmony_ci -err, errbuf, 8898c2ecf20Sopenharmony_ci sizeof(errbuf)); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci parse_events__handle_error(parse_state->error, 0, 8928c2ecf20Sopenharmony_ci strdup(errbuf), strdup("(add -v to see detail)")); 8938c2ecf20Sopenharmony_ci return err; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci err = parse_events_load_bpf_obj(parse_state, list, obj, head_config); 8978c2ecf20Sopenharmony_ci if (err) 8988c2ecf20Sopenharmony_ci return err; 8998c2ecf20Sopenharmony_ci err = parse_events_config_bpf(parse_state, obj, &obj_head_config); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* 9028c2ecf20Sopenharmony_ci * Caller doesn't know anything about obj_head_config, 9038c2ecf20Sopenharmony_ci * so combine them together again before returnning. 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_ci if (head_config) 9068c2ecf20Sopenharmony_ci list_splice_tail(&obj_head_config, head_config); 9078c2ecf20Sopenharmony_ci return err; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic int 9118c2ecf20Sopenharmony_ciparse_breakpoint_type(const char *type, struct perf_event_attr *attr) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci int i; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 9168c2ecf20Sopenharmony_ci if (!type || !type[i]) 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci#define CHECK_SET_TYPE(bit) \ 9208c2ecf20Sopenharmony_cido { \ 9218c2ecf20Sopenharmony_ci if (attr->bp_type & bit) \ 9228c2ecf20Sopenharmony_ci return -EINVAL; \ 9238c2ecf20Sopenharmony_ci else \ 9248c2ecf20Sopenharmony_ci attr->bp_type |= bit; \ 9258c2ecf20Sopenharmony_ci} while (0) 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci switch (type[i]) { 9288c2ecf20Sopenharmony_ci case 'r': 9298c2ecf20Sopenharmony_ci CHECK_SET_TYPE(HW_BREAKPOINT_R); 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci case 'w': 9328c2ecf20Sopenharmony_ci CHECK_SET_TYPE(HW_BREAKPOINT_W); 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci case 'x': 9358c2ecf20Sopenharmony_ci CHECK_SET_TYPE(HW_BREAKPOINT_X); 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci default: 9388c2ecf20Sopenharmony_ci return -EINVAL; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci#undef CHECK_SET_TYPE 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (!attr->bp_type) /* Default */ 9458c2ecf20Sopenharmony_ci attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ciint parse_events_add_breakpoint(struct list_head *list, int *idx, 9518c2ecf20Sopenharmony_ci u64 addr, char *type, u64 len) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct perf_event_attr attr; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 9568c2ecf20Sopenharmony_ci attr.bp_addr = addr; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (parse_breakpoint_type(type, &attr)) 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* Provide some defaults if len is not specified */ 9628c2ecf20Sopenharmony_ci if (!len) { 9638c2ecf20Sopenharmony_ci if (attr.bp_type == HW_BREAKPOINT_X) 9648c2ecf20Sopenharmony_ci len = sizeof(long); 9658c2ecf20Sopenharmony_ci else 9668c2ecf20Sopenharmony_ci len = HW_BREAKPOINT_LEN_4; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci attr.bp_len = len; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci attr.type = PERF_TYPE_BREAKPOINT; 9728c2ecf20Sopenharmony_ci attr.sample_period = 1; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return add_event(list, idx, &attr, NULL, NULL); 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic int check_type_val(struct parse_events_term *term, 9788c2ecf20Sopenharmony_ci struct parse_events_error *err, 9798c2ecf20Sopenharmony_ci int type) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci if (type == term->type_val) 9828c2ecf20Sopenharmony_ci return 0; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (err) { 9858c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_val, 9868c2ecf20Sopenharmony_ci type == PARSE_EVENTS__TERM_TYPE_NUM 9878c2ecf20Sopenharmony_ci ? strdup("expected numeric value") 9888c2ecf20Sopenharmony_ci : strdup("expected string value"), 9898c2ecf20Sopenharmony_ci NULL); 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci return -EINVAL; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci/* 9958c2ecf20Sopenharmony_ci * Update according to parse-events.l 9968c2ecf20Sopenharmony_ci */ 9978c2ecf20Sopenharmony_cistatic const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { 9988c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_USER] = "<sysfs term>", 9998c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_CONFIG] = "config", 10008c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_CONFIG1] = "config1", 10018c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_CONFIG2] = "config2", 10028c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_NAME] = "name", 10038c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD] = "period", 10048c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ] = "freq", 10058c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE] = "branch_type", 10068c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_TIME] = "time", 10078c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_CALLGRAPH] = "call-graph", 10088c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size", 10098c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", 10108c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", 10118c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", 10128c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr", 10138c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", 10148c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", 10158c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", 10168c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_PERCORE] = "percore", 10178c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT] = "aux-output", 10188c2ecf20Sopenharmony_ci [PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE] = "aux-sample-size", 10198c2ecf20Sopenharmony_ci}; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic bool config_term_shrinked; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic bool 10248c2ecf20Sopenharmony_ciconfig_term_avail(int term_type, struct parse_events_error *err) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci char *err_str; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (term_type < 0 || term_type >= __PARSE_EVENTS__TERM_TYPE_NR) { 10298c2ecf20Sopenharmony_ci parse_events__handle_error(err, -1, 10308c2ecf20Sopenharmony_ci strdup("Invalid term_type"), NULL); 10318c2ecf20Sopenharmony_ci return false; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci if (!config_term_shrinked) 10348c2ecf20Sopenharmony_ci return true; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci switch (term_type) { 10378c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG: 10388c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG1: 10398c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG2: 10408c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NAME: 10418c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 10428c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_PERCORE: 10438c2ecf20Sopenharmony_ci return true; 10448c2ecf20Sopenharmony_ci default: 10458c2ecf20Sopenharmony_ci if (!err) 10468c2ecf20Sopenharmony_ci return false; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci /* term_type is validated so indexing is safe */ 10498c2ecf20Sopenharmony_ci if (asprintf(&err_str, "'%s' is not usable in 'perf stat'", 10508c2ecf20Sopenharmony_ci config_term_names[term_type]) >= 0) 10518c2ecf20Sopenharmony_ci parse_events__handle_error(err, -1, err_str, NULL); 10528c2ecf20Sopenharmony_ci return false; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_civoid parse_events__shrink_config_terms(void) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci config_term_shrinked = true; 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic int config_term_common(struct perf_event_attr *attr, 10628c2ecf20Sopenharmony_ci struct parse_events_term *term, 10638c2ecf20Sopenharmony_ci struct parse_events_error *err) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci#define CHECK_TYPE_VAL(type) \ 10668c2ecf20Sopenharmony_cido { \ 10678c2ecf20Sopenharmony_ci if (check_type_val(term, err, PARSE_EVENTS__TERM_TYPE_ ## type)) \ 10688c2ecf20Sopenharmony_ci return -EINVAL; \ 10698c2ecf20Sopenharmony_ci} while (0) 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci switch (term->type_term) { 10728c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG: 10738c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 10748c2ecf20Sopenharmony_ci attr->config = term->val.num; 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG1: 10778c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 10788c2ecf20Sopenharmony_ci attr->config1 = term->val.num; 10798c2ecf20Sopenharmony_ci break; 10808c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG2: 10818c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 10828c2ecf20Sopenharmony_ci attr->config2 = term->val.num; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 10858c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ: 10888c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 10918c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(STR); 10928c2ecf20Sopenharmony_ci if (strcmp(term->val.str, "no") && 10938c2ecf20Sopenharmony_ci parse_branch_str(term->val.str, 10948c2ecf20Sopenharmony_ci &attr->branch_sample_type)) { 10958c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_val, 10968c2ecf20Sopenharmony_ci strdup("invalid branch sample type"), 10978c2ecf20Sopenharmony_ci NULL); 10988c2ecf20Sopenharmony_ci return -EINVAL; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_TIME: 11028c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11038c2ecf20Sopenharmony_ci if (term->val.num > 1) { 11048c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_val, 11058c2ecf20Sopenharmony_ci strdup("expected 0 or 1"), 11068c2ecf20Sopenharmony_ci NULL); 11078c2ecf20Sopenharmony_ci return -EINVAL; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci break; 11108c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: 11118c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(STR); 11128c2ecf20Sopenharmony_ci break; 11138c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 11148c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_INHERIT: 11178c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11188c2ecf20Sopenharmony_ci break; 11198c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 11208c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11218c2ecf20Sopenharmony_ci break; 11228c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 11238c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: 11268c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11278c2ecf20Sopenharmony_ci break; 11288c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NAME: 11298c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(STR); 11308c2ecf20Sopenharmony_ci break; 11318c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 11328c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11338c2ecf20Sopenharmony_ci break; 11348c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 11358c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_PERCORE: 11388c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11398c2ecf20Sopenharmony_ci if ((unsigned int)term->val.num > 1) { 11408c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_val, 11418c2ecf20Sopenharmony_ci strdup("expected 0 or 1"), 11428c2ecf20Sopenharmony_ci NULL); 11438c2ecf20Sopenharmony_ci return -EINVAL; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: 11478c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: 11508c2ecf20Sopenharmony_ci CHECK_TYPE_VAL(NUM); 11518c2ecf20Sopenharmony_ci if (term->val.num > UINT_MAX) { 11528c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_val, 11538c2ecf20Sopenharmony_ci strdup("too big"), 11548c2ecf20Sopenharmony_ci NULL); 11558c2ecf20Sopenharmony_ci return -EINVAL; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci default: 11598c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_term, 11608c2ecf20Sopenharmony_ci strdup("unknown term"), 11618c2ecf20Sopenharmony_ci parse_events_formats_error_string(NULL)); 11628c2ecf20Sopenharmony_ci return -EINVAL; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* 11668c2ecf20Sopenharmony_ci * Check term availbility after basic checking so 11678c2ecf20Sopenharmony_ci * PARSE_EVENTS__TERM_TYPE_USER can be found and filtered. 11688c2ecf20Sopenharmony_ci * 11698c2ecf20Sopenharmony_ci * If check availbility at the entry of this function, 11708c2ecf20Sopenharmony_ci * user will see "'<sysfs term>' is not usable in 'perf stat'" 11718c2ecf20Sopenharmony_ci * if an invalid config term is provided for legacy events 11728c2ecf20Sopenharmony_ci * (for example, instructions/badterm/...), which is confusing. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci if (!config_term_avail(term->type_term, err)) 11758c2ecf20Sopenharmony_ci return -EINVAL; 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci#undef CHECK_TYPE_VAL 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic int config_term_pmu(struct perf_event_attr *attr, 11818c2ecf20Sopenharmony_ci struct parse_events_term *term, 11828c2ecf20Sopenharmony_ci struct parse_events_error *err) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER || 11858c2ecf20Sopenharmony_ci term->type_term == PARSE_EVENTS__TERM_TYPE_DRV_CFG) 11868c2ecf20Sopenharmony_ci /* 11878c2ecf20Sopenharmony_ci * Always succeed for sysfs terms, as we dont know 11888c2ecf20Sopenharmony_ci * at this point what type they need to have. 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci return 0; 11918c2ecf20Sopenharmony_ci else 11928c2ecf20Sopenharmony_ci return config_term_common(attr, term, err); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic int config_term_tracepoint(struct perf_event_attr *attr, 11968c2ecf20Sopenharmony_ci struct parse_events_term *term, 11978c2ecf20Sopenharmony_ci struct parse_events_error *err) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci switch (term->type_term) { 12008c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: 12018c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 12028c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_INHERIT: 12038c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 12048c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 12058c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 12068c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 12078c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: 12088c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: 12098c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: 12108c2ecf20Sopenharmony_ci return config_term_common(attr, term, err); 12118c2ecf20Sopenharmony_ci default: 12128c2ecf20Sopenharmony_ci if (err) { 12138c2ecf20Sopenharmony_ci parse_events__handle_error(err, term->err_term, 12148c2ecf20Sopenharmony_ci strdup("unknown term"), 12158c2ecf20Sopenharmony_ci strdup("valid terms: call-graph,stack-size\n")); 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci return -EINVAL; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci return 0; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic int config_attr(struct perf_event_attr *attr, 12248c2ecf20Sopenharmony_ci struct list_head *head, 12258c2ecf20Sopenharmony_ci struct parse_events_error *err, 12268c2ecf20Sopenharmony_ci config_term_func_t config_term) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci struct parse_events_term *term; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci list_for_each_entry(term, head, list) 12318c2ecf20Sopenharmony_ci if (config_term(attr, term, err)) 12328c2ecf20Sopenharmony_ci return -EINVAL; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci return 0; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int get_config_terms(struct list_head *head_config, 12388c2ecf20Sopenharmony_ci struct list_head *head_terms __maybe_unused) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci#define ADD_CONFIG_TERM(__type, __weak) \ 12418c2ecf20Sopenharmony_ci struct evsel_config_term *__t; \ 12428c2ecf20Sopenharmony_ci \ 12438c2ecf20Sopenharmony_ci __t = zalloc(sizeof(*__t)); \ 12448c2ecf20Sopenharmony_ci if (!__t) \ 12458c2ecf20Sopenharmony_ci return -ENOMEM; \ 12468c2ecf20Sopenharmony_ci \ 12478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&__t->list); \ 12488c2ecf20Sopenharmony_ci __t->type = EVSEL__CONFIG_TERM_ ## __type; \ 12498c2ecf20Sopenharmony_ci __t->weak = __weak; \ 12508c2ecf20Sopenharmony_ci list_add_tail(&__t->list, head_terms) 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak) \ 12538c2ecf20Sopenharmony_cido { \ 12548c2ecf20Sopenharmony_ci ADD_CONFIG_TERM(__type, __weak); \ 12558c2ecf20Sopenharmony_ci __t->val.__name = __val; \ 12568c2ecf20Sopenharmony_ci} while (0) 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci#define ADD_CONFIG_TERM_STR(__type, __val, __weak) \ 12598c2ecf20Sopenharmony_cido { \ 12608c2ecf20Sopenharmony_ci ADD_CONFIG_TERM(__type, __weak); \ 12618c2ecf20Sopenharmony_ci __t->val.str = strdup(__val); \ 12628c2ecf20Sopenharmony_ci if (!__t->val.str) { \ 12638c2ecf20Sopenharmony_ci zfree(&__t); \ 12648c2ecf20Sopenharmony_ci return -ENOMEM; \ 12658c2ecf20Sopenharmony_ci } \ 12668c2ecf20Sopenharmony_ci __t->free_str = true; \ 12678c2ecf20Sopenharmony_ci} while (0) 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci struct parse_events_term *term; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci list_for_each_entry(term, head_config, list) { 12728c2ecf20Sopenharmony_ci switch (term->type_term) { 12738c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 12748c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak); 12758c2ecf20Sopenharmony_ci break; 12768c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ: 12778c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak); 12788c2ecf20Sopenharmony_ci break; 12798c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_TIME: 12808c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak); 12818c2ecf20Sopenharmony_ci break; 12828c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: 12838c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak); 12848c2ecf20Sopenharmony_ci break; 12858c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 12868c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak); 12878c2ecf20Sopenharmony_ci break; 12888c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_STACKSIZE: 12898c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(STACK_USER, stack_user, 12908c2ecf20Sopenharmony_ci term->val.num, term->weak); 12918c2ecf20Sopenharmony_ci break; 12928c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_INHERIT: 12938c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(INHERIT, inherit, 12948c2ecf20Sopenharmony_ci term->val.num ? 1 : 0, term->weak); 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NOINHERIT: 12978c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(INHERIT, inherit, 12988c2ecf20Sopenharmony_ci term->val.num ? 0 : 1, term->weak); 12998c2ecf20Sopenharmony_ci break; 13008c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_MAX_STACK: 13018c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack, 13028c2ecf20Sopenharmony_ci term->val.num, term->weak); 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: 13058c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events, 13068c2ecf20Sopenharmony_ci term->val.num, term->weak); 13078c2ecf20Sopenharmony_ci break; 13088c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_OVERWRITE: 13098c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite, 13108c2ecf20Sopenharmony_ci term->val.num ? 1 : 0, term->weak); 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: 13138c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite, 13148c2ecf20Sopenharmony_ci term->val.num ? 0 : 1, term->weak); 13158c2ecf20Sopenharmony_ci break; 13168c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_DRV_CFG: 13178c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak); 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_PERCORE: 13208c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(PERCORE, percore, 13218c2ecf20Sopenharmony_ci term->val.num ? true : false, term->weak); 13228c2ecf20Sopenharmony_ci break; 13238c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: 13248c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output, 13258c2ecf20Sopenharmony_ci term->val.num ? 1 : 0, term->weak); 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: 13288c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size, 13298c2ecf20Sopenharmony_ci term->val.num, term->weak); 13308c2ecf20Sopenharmony_ci break; 13318c2ecf20Sopenharmony_ci default: 13328c2ecf20Sopenharmony_ci break; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci return 0; 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci/* 13398c2ecf20Sopenharmony_ci * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for 13408c2ecf20Sopenharmony_ci * each bit of attr->config that the user has changed. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_cistatic int get_config_chgs(struct perf_pmu *pmu, struct list_head *head_config, 13438c2ecf20Sopenharmony_ci struct list_head *head_terms) 13448c2ecf20Sopenharmony_ci{ 13458c2ecf20Sopenharmony_ci struct parse_events_term *term; 13468c2ecf20Sopenharmony_ci u64 bits = 0; 13478c2ecf20Sopenharmony_ci int type; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci list_for_each_entry(term, head_config, list) { 13508c2ecf20Sopenharmony_ci switch (term->type_term) { 13518c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_USER: 13528c2ecf20Sopenharmony_ci type = perf_pmu__format_type(&pmu->format, term->config); 13538c2ecf20Sopenharmony_ci if (type != PERF_PMU_FORMAT_VALUE_CONFIG) 13548c2ecf20Sopenharmony_ci continue; 13558c2ecf20Sopenharmony_ci bits |= perf_pmu__format_bits(&pmu->format, term->config); 13568c2ecf20Sopenharmony_ci break; 13578c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_CONFIG: 13588c2ecf20Sopenharmony_ci bits = ~(u64)0; 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci default: 13618c2ecf20Sopenharmony_ci break; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (bits) 13668c2ecf20Sopenharmony_ci ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci#undef ADD_CONFIG_TERM 13698c2ecf20Sopenharmony_ci return 0; 13708c2ecf20Sopenharmony_ci} 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ciint parse_events_add_tracepoint(struct list_head *list, int *idx, 13738c2ecf20Sopenharmony_ci const char *sys, const char *event, 13748c2ecf20Sopenharmony_ci struct parse_events_error *err, 13758c2ecf20Sopenharmony_ci struct list_head *head_config) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci if (head_config) { 13788c2ecf20Sopenharmony_ci struct perf_event_attr attr; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (config_attr(&attr, head_config, err, 13818c2ecf20Sopenharmony_ci config_term_tracepoint)) 13828c2ecf20Sopenharmony_ci return -EINVAL; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (strpbrk(sys, "*?")) 13868c2ecf20Sopenharmony_ci return add_tracepoint_multi_sys(list, idx, sys, event, 13878c2ecf20Sopenharmony_ci err, head_config); 13888c2ecf20Sopenharmony_ci else 13898c2ecf20Sopenharmony_ci return add_tracepoint_event(list, idx, sys, event, 13908c2ecf20Sopenharmony_ci err, head_config); 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ciint parse_events_add_numeric(struct parse_events_state *parse_state, 13948c2ecf20Sopenharmony_ci struct list_head *list, 13958c2ecf20Sopenharmony_ci u32 type, u64 config, 13968c2ecf20Sopenharmony_ci struct list_head *head_config) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci struct perf_event_attr attr; 13998c2ecf20Sopenharmony_ci LIST_HEAD(config_terms); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 14028c2ecf20Sopenharmony_ci attr.type = type; 14038c2ecf20Sopenharmony_ci attr.config = config; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (head_config) { 14068c2ecf20Sopenharmony_ci if (config_attr(&attr, head_config, parse_state->error, 14078c2ecf20Sopenharmony_ci config_term_common)) 14088c2ecf20Sopenharmony_ci return -EINVAL; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (get_config_terms(head_config, &config_terms)) 14118c2ecf20Sopenharmony_ci return -ENOMEM; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci return add_event(list, &parse_state->idx, &attr, 14158c2ecf20Sopenharmony_ci get_config_name(head_config), &config_terms); 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ciint parse_events_add_tool(struct parse_events_state *parse_state, 14198c2ecf20Sopenharmony_ci struct list_head *list, 14208c2ecf20Sopenharmony_ci enum perf_tool_event tool_event) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci return add_event_tool(list, &parse_state->idx, tool_event); 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_cistatic bool config_term_percore(struct list_head *config_terms) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct evsel_config_term *term; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci list_for_each_entry(term, config_terms, list) { 14308c2ecf20Sopenharmony_ci if (term->type == EVSEL__CONFIG_TERM_PERCORE) 14318c2ecf20Sopenharmony_ci return term->val.percore; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci return false; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ciint parse_events_add_pmu(struct parse_events_state *parse_state, 14388c2ecf20Sopenharmony_ci struct list_head *list, char *name, 14398c2ecf20Sopenharmony_ci struct list_head *head_config, 14408c2ecf20Sopenharmony_ci bool auto_merge_stats, 14418c2ecf20Sopenharmony_ci bool use_alias) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci struct perf_event_attr attr; 14448c2ecf20Sopenharmony_ci struct perf_pmu_info info; 14458c2ecf20Sopenharmony_ci struct perf_pmu *pmu; 14468c2ecf20Sopenharmony_ci struct evsel *evsel; 14478c2ecf20Sopenharmony_ci struct parse_events_error *err = parse_state->error; 14488c2ecf20Sopenharmony_ci bool use_uncore_alias; 14498c2ecf20Sopenharmony_ci LIST_HEAD(config_terms); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci pmu = parse_state->fake_pmu ?: perf_pmu__find(name); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci if (verbose > 1 && !(pmu && pmu->selectable)) { 14548c2ecf20Sopenharmony_ci fprintf(stderr, "Attempting to add event pmu '%s' with '", 14558c2ecf20Sopenharmony_ci name); 14568c2ecf20Sopenharmony_ci if (head_config) { 14578c2ecf20Sopenharmony_ci struct parse_events_term *term; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci list_for_each_entry(term, head_config, list) { 14608c2ecf20Sopenharmony_ci fprintf(stderr, "%s,", term->config); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci fprintf(stderr, "' that may result in non-fatal errors\n"); 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (!pmu) { 14678c2ecf20Sopenharmony_ci char *err_str; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if (asprintf(&err_str, 14708c2ecf20Sopenharmony_ci "Cannot find PMU `%s'. Missing kernel support?", 14718c2ecf20Sopenharmony_ci name) >= 0) 14728c2ecf20Sopenharmony_ci parse_events__handle_error(err, 0, err_str, NULL); 14738c2ecf20Sopenharmony_ci return -EINVAL; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (pmu->default_config) { 14778c2ecf20Sopenharmony_ci memcpy(&attr, pmu->default_config, 14788c2ecf20Sopenharmony_ci sizeof(struct perf_event_attr)); 14798c2ecf20Sopenharmony_ci } else { 14808c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci use_uncore_alias = (pmu->is_uncore && use_alias); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci if (!head_config) { 14868c2ecf20Sopenharmony_ci attr.type = pmu->type; 14878c2ecf20Sopenharmony_ci evsel = __add_event(list, &parse_state->idx, &attr, true, NULL, 14888c2ecf20Sopenharmony_ci pmu, NULL, auto_merge_stats, NULL); 14898c2ecf20Sopenharmony_ci if (evsel) { 14908c2ecf20Sopenharmony_ci evsel->pmu_name = name ? strdup(name) : NULL; 14918c2ecf20Sopenharmony_ci evsel->use_uncore_alias = use_uncore_alias; 14928c2ecf20Sopenharmony_ci return 0; 14938c2ecf20Sopenharmony_ci } else { 14948c2ecf20Sopenharmony_ci return -ENOMEM; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, head_config, &info)) 14998c2ecf20Sopenharmony_ci return -EINVAL; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (verbose > 1) { 15028c2ecf20Sopenharmony_ci fprintf(stderr, "After aliases, add event pmu '%s' with '", 15038c2ecf20Sopenharmony_ci name); 15048c2ecf20Sopenharmony_ci if (head_config) { 15058c2ecf20Sopenharmony_ci struct parse_events_term *term; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci list_for_each_entry(term, head_config, list) { 15088c2ecf20Sopenharmony_ci fprintf(stderr, "%s,", term->config); 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci fprintf(stderr, "' that may result in non-fatal errors\n"); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci /* 15158c2ecf20Sopenharmony_ci * Configure hardcoded terms first, no need to check 15168c2ecf20Sopenharmony_ci * return value when called with fail == 0 ;) 15178c2ecf20Sopenharmony_ci */ 15188c2ecf20Sopenharmony_ci if (config_attr(&attr, head_config, parse_state->error, config_term_pmu)) 15198c2ecf20Sopenharmony_ci return -EINVAL; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (get_config_terms(head_config, &config_terms)) 15228c2ecf20Sopenharmony_ci return -ENOMEM; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci /* 15258c2ecf20Sopenharmony_ci * When using default config, record which bits of attr->config were 15268c2ecf20Sopenharmony_ci * changed by the user. 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci if (pmu->default_config && get_config_chgs(pmu, head_config, &config_terms)) 15298c2ecf20Sopenharmony_ci return -ENOMEM; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (!parse_state->fake_pmu && perf_pmu__config(pmu, &attr, head_config, parse_state->error)) { 15328c2ecf20Sopenharmony_ci struct evsel_config_term *pos, *tmp; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, tmp, &config_terms, list) { 15358c2ecf20Sopenharmony_ci list_del_init(&pos->list); 15368c2ecf20Sopenharmony_ci if (pos->free_str) 15378c2ecf20Sopenharmony_ci zfree(&pos->val.str); 15388c2ecf20Sopenharmony_ci free(pos); 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci return -EINVAL; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci evsel = __add_event(list, &parse_state->idx, &attr, true, 15448c2ecf20Sopenharmony_ci get_config_name(head_config), pmu, 15458c2ecf20Sopenharmony_ci &config_terms, auto_merge_stats, NULL); 15468c2ecf20Sopenharmony_ci if (!evsel) 15478c2ecf20Sopenharmony_ci return -ENOMEM; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci evsel->pmu_name = name ? strdup(name) : NULL; 15508c2ecf20Sopenharmony_ci evsel->use_uncore_alias = use_uncore_alias; 15518c2ecf20Sopenharmony_ci evsel->percore = config_term_percore(&evsel->config_terms); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (parse_state->fake_pmu) 15548c2ecf20Sopenharmony_ci return 0; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci evsel->unit = info.unit; 15578c2ecf20Sopenharmony_ci evsel->scale = info.scale; 15588c2ecf20Sopenharmony_ci evsel->per_pkg = info.per_pkg; 15598c2ecf20Sopenharmony_ci evsel->snapshot = info.snapshot; 15608c2ecf20Sopenharmony_ci evsel->metric_expr = info.metric_expr; 15618c2ecf20Sopenharmony_ci evsel->metric_name = info.metric_name; 15628c2ecf20Sopenharmony_ci return 0; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ciint parse_events_multi_pmu_add(struct parse_events_state *parse_state, 15668c2ecf20Sopenharmony_ci char *str, struct list_head **listp) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci struct parse_events_term *term; 15698c2ecf20Sopenharmony_ci struct list_head *list; 15708c2ecf20Sopenharmony_ci struct perf_pmu *pmu = NULL; 15718c2ecf20Sopenharmony_ci int ok = 0; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci *listp = NULL; 15748c2ecf20Sopenharmony_ci /* Add it for all PMUs that support the alias */ 15758c2ecf20Sopenharmony_ci list = malloc(sizeof(struct list_head)); 15768c2ecf20Sopenharmony_ci if (!list) 15778c2ecf20Sopenharmony_ci return -1; 15788c2ecf20Sopenharmony_ci INIT_LIST_HEAD(list); 15798c2ecf20Sopenharmony_ci while ((pmu = perf_pmu__scan(pmu)) != NULL) { 15808c2ecf20Sopenharmony_ci struct perf_pmu_alias *alias; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci list_for_each_entry(alias, &pmu->aliases, list) { 15838c2ecf20Sopenharmony_ci if (!strcasecmp(alias->name, str)) { 15848c2ecf20Sopenharmony_ci struct list_head *head; 15858c2ecf20Sopenharmony_ci char *config; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci head = malloc(sizeof(struct list_head)); 15888c2ecf20Sopenharmony_ci if (!head) 15898c2ecf20Sopenharmony_ci return -1; 15908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(head); 15918c2ecf20Sopenharmony_ci config = strdup(str); 15928c2ecf20Sopenharmony_ci if (!config) 15938c2ecf20Sopenharmony_ci return -1; 15948c2ecf20Sopenharmony_ci if (parse_events_term__num(&term, 15958c2ecf20Sopenharmony_ci PARSE_EVENTS__TERM_TYPE_USER, 15968c2ecf20Sopenharmony_ci config, 1, false, &config, 15978c2ecf20Sopenharmony_ci NULL) < 0) { 15988c2ecf20Sopenharmony_ci free(list); 15998c2ecf20Sopenharmony_ci free(config); 16008c2ecf20Sopenharmony_ci return -1; 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci list_add_tail(&term->list, head); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (!parse_events_add_pmu(parse_state, list, 16058c2ecf20Sopenharmony_ci pmu->name, head, 16068c2ecf20Sopenharmony_ci true, true)) { 16078c2ecf20Sopenharmony_ci pr_debug("%s -> %s/%s/\n", str, 16088c2ecf20Sopenharmony_ci pmu->name, alias->str); 16098c2ecf20Sopenharmony_ci ok++; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci parse_events_terms__delete(head); 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci if (!ok) { 16178c2ecf20Sopenharmony_ci free(list); 16188c2ecf20Sopenharmony_ci return -1; 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci *listp = list; 16218c2ecf20Sopenharmony_ci return 0; 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ciint parse_events__modifier_group(struct list_head *list, 16258c2ecf20Sopenharmony_ci char *event_mod) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci return parse_events__modifier_event(list, event_mod, true); 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci/* 16318c2ecf20Sopenharmony_ci * Check if the two uncore PMUs are from the same uncore block 16328c2ecf20Sopenharmony_ci * The format of the uncore PMU name is uncore_#blockname_#pmuidx 16338c2ecf20Sopenharmony_ci */ 16348c2ecf20Sopenharmony_cistatic bool is_same_uncore_block(const char *pmu_name_a, const char *pmu_name_b) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci char *end_a, *end_b; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci end_a = strrchr(pmu_name_a, '_'); 16398c2ecf20Sopenharmony_ci end_b = strrchr(pmu_name_b, '_'); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if (!end_a || !end_b) 16428c2ecf20Sopenharmony_ci return false; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if ((end_a - pmu_name_a) != (end_b - pmu_name_b)) 16458c2ecf20Sopenharmony_ci return false; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return (strncmp(pmu_name_a, pmu_name_b, end_a - pmu_name_a) == 0); 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic int 16518c2ecf20Sopenharmony_ciparse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, 16528c2ecf20Sopenharmony_ci struct parse_events_state *parse_state) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci struct evsel *evsel, *leader; 16558c2ecf20Sopenharmony_ci uintptr_t *leaders; 16568c2ecf20Sopenharmony_ci bool is_leader = true; 16578c2ecf20Sopenharmony_ci int i, nr_pmu = 0, total_members, ret = 0; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci leader = list_first_entry(list, struct evsel, core.node); 16608c2ecf20Sopenharmony_ci evsel = list_last_entry(list, struct evsel, core.node); 16618c2ecf20Sopenharmony_ci total_members = evsel->idx - leader->idx + 1; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci leaders = calloc(total_members, sizeof(uintptr_t)); 16648c2ecf20Sopenharmony_ci if (WARN_ON(!leaders)) 16658c2ecf20Sopenharmony_ci return 0; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci /* 16688c2ecf20Sopenharmony_ci * Going through the whole group and doing sanity check. 16698c2ecf20Sopenharmony_ci * All members must use alias, and be from the same uncore block. 16708c2ecf20Sopenharmony_ci * Also, storing the leader events in an array. 16718c2ecf20Sopenharmony_ci */ 16728c2ecf20Sopenharmony_ci __evlist__for_each_entry(list, evsel) { 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* Only split the uncore group which members use alias */ 16758c2ecf20Sopenharmony_ci if (!evsel->use_uncore_alias) 16768c2ecf20Sopenharmony_ci goto out; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* The events must be from the same uncore block */ 16798c2ecf20Sopenharmony_ci if (!is_same_uncore_block(leader->pmu_name, evsel->pmu_name)) 16808c2ecf20Sopenharmony_ci goto out; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (!is_leader) 16838c2ecf20Sopenharmony_ci continue; 16848c2ecf20Sopenharmony_ci /* 16858c2ecf20Sopenharmony_ci * If the event's PMU name starts to repeat, it must be a new 16868c2ecf20Sopenharmony_ci * event. That can be used to distinguish the leader from 16878c2ecf20Sopenharmony_ci * other members, even they have the same event name. 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ci if ((leader != evsel) && 16908c2ecf20Sopenharmony_ci !strcmp(leader->pmu_name, evsel->pmu_name)) { 16918c2ecf20Sopenharmony_ci is_leader = false; 16928c2ecf20Sopenharmony_ci continue; 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci /* Store the leader event for each PMU */ 16968c2ecf20Sopenharmony_ci leaders[nr_pmu++] = (uintptr_t) evsel; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* only one event alias */ 17008c2ecf20Sopenharmony_ci if (nr_pmu == total_members) { 17018c2ecf20Sopenharmony_ci parse_state->nr_groups--; 17028c2ecf20Sopenharmony_ci goto handled; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* 17068c2ecf20Sopenharmony_ci * An uncore event alias is a joint name which means the same event 17078c2ecf20Sopenharmony_ci * runs on all PMUs of a block. 17088c2ecf20Sopenharmony_ci * Perf doesn't support mixed events from different PMUs in the same 17098c2ecf20Sopenharmony_ci * group. The big group has to be split into multiple small groups 17108c2ecf20Sopenharmony_ci * which only include the events from the same PMU. 17118c2ecf20Sopenharmony_ci * 17128c2ecf20Sopenharmony_ci * Here the uncore event aliases must be from the same uncore block. 17138c2ecf20Sopenharmony_ci * The number of PMUs must be same for each alias. The number of new 17148c2ecf20Sopenharmony_ci * small groups equals to the number of PMUs. 17158c2ecf20Sopenharmony_ci * Setting the leader event for corresponding members in each group. 17168c2ecf20Sopenharmony_ci */ 17178c2ecf20Sopenharmony_ci i = 0; 17188c2ecf20Sopenharmony_ci __evlist__for_each_entry(list, evsel) { 17198c2ecf20Sopenharmony_ci if (i >= nr_pmu) 17208c2ecf20Sopenharmony_ci i = 0; 17218c2ecf20Sopenharmony_ci evsel->leader = (struct evsel *) leaders[i++]; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci /* The number of members and group name are same for each group */ 17258c2ecf20Sopenharmony_ci for (i = 0; i < nr_pmu; i++) { 17268c2ecf20Sopenharmony_ci evsel = (struct evsel *) leaders[i]; 17278c2ecf20Sopenharmony_ci evsel->core.nr_members = total_members / nr_pmu; 17288c2ecf20Sopenharmony_ci evsel->group_name = name ? strdup(name) : NULL; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* Take the new small groups into account */ 17328c2ecf20Sopenharmony_ci parse_state->nr_groups += nr_pmu - 1; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_cihandled: 17358c2ecf20Sopenharmony_ci ret = 1; 17368c2ecf20Sopenharmony_ciout: 17378c2ecf20Sopenharmony_ci free(leaders); 17388c2ecf20Sopenharmony_ci return ret; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_civoid parse_events__set_leader(char *name, struct list_head *list, 17428c2ecf20Sopenharmony_ci struct parse_events_state *parse_state) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci struct evsel *leader; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (list_empty(list)) { 17478c2ecf20Sopenharmony_ci WARN_ONCE(true, "WARNING: failed to set leader: empty list"); 17488c2ecf20Sopenharmony_ci return; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (parse_events__set_leader_for_uncore_aliase(name, list, parse_state)) 17528c2ecf20Sopenharmony_ci return; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci __perf_evlist__set_leader(list); 17558c2ecf20Sopenharmony_ci leader = list_entry(list->next, struct evsel, core.node); 17568c2ecf20Sopenharmony_ci leader->group_name = name ? strdup(name) : NULL; 17578c2ecf20Sopenharmony_ci} 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci/* list_event is assumed to point to malloc'ed memory */ 17608c2ecf20Sopenharmony_civoid parse_events_update_lists(struct list_head *list_event, 17618c2ecf20Sopenharmony_ci struct list_head *list_all) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci /* 17648c2ecf20Sopenharmony_ci * Called for single event definition. Update the 17658c2ecf20Sopenharmony_ci * 'all event' list, and reinit the 'single event' 17668c2ecf20Sopenharmony_ci * list, for next event definition. 17678c2ecf20Sopenharmony_ci */ 17688c2ecf20Sopenharmony_ci list_splice_tail(list_event, list_all); 17698c2ecf20Sopenharmony_ci free(list_event); 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_cistruct event_modifier { 17738c2ecf20Sopenharmony_ci int eu; 17748c2ecf20Sopenharmony_ci int ek; 17758c2ecf20Sopenharmony_ci int eh; 17768c2ecf20Sopenharmony_ci int eH; 17778c2ecf20Sopenharmony_ci int eG; 17788c2ecf20Sopenharmony_ci int eI; 17798c2ecf20Sopenharmony_ci int precise; 17808c2ecf20Sopenharmony_ci int precise_max; 17818c2ecf20Sopenharmony_ci int exclude_GH; 17828c2ecf20Sopenharmony_ci int sample_read; 17838c2ecf20Sopenharmony_ci int pinned; 17848c2ecf20Sopenharmony_ci int weak; 17858c2ecf20Sopenharmony_ci int exclusive; 17868c2ecf20Sopenharmony_ci}; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic int get_event_modifier(struct event_modifier *mod, char *str, 17898c2ecf20Sopenharmony_ci struct evsel *evsel) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci int eu = evsel ? evsel->core.attr.exclude_user : 0; 17928c2ecf20Sopenharmony_ci int ek = evsel ? evsel->core.attr.exclude_kernel : 0; 17938c2ecf20Sopenharmony_ci int eh = evsel ? evsel->core.attr.exclude_hv : 0; 17948c2ecf20Sopenharmony_ci int eH = evsel ? evsel->core.attr.exclude_host : 0; 17958c2ecf20Sopenharmony_ci int eG = evsel ? evsel->core.attr.exclude_guest : 0; 17968c2ecf20Sopenharmony_ci int eI = evsel ? evsel->core.attr.exclude_idle : 0; 17978c2ecf20Sopenharmony_ci int precise = evsel ? evsel->core.attr.precise_ip : 0; 17988c2ecf20Sopenharmony_ci int precise_max = 0; 17998c2ecf20Sopenharmony_ci int sample_read = 0; 18008c2ecf20Sopenharmony_ci int pinned = evsel ? evsel->core.attr.pinned : 0; 18018c2ecf20Sopenharmony_ci int exclusive = evsel ? evsel->core.attr.exclusive : 0; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci int exclude = eu | ek | eh; 18048c2ecf20Sopenharmony_ci int exclude_GH = evsel ? evsel->exclude_GH : 0; 18058c2ecf20Sopenharmony_ci int weak = 0; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci memset(mod, 0, sizeof(*mod)); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci while (*str) { 18108c2ecf20Sopenharmony_ci if (*str == 'u') { 18118c2ecf20Sopenharmony_ci if (!exclude) 18128c2ecf20Sopenharmony_ci exclude = eu = ek = eh = 1; 18138c2ecf20Sopenharmony_ci if (!exclude_GH && !perf_guest) 18148c2ecf20Sopenharmony_ci eG = 1; 18158c2ecf20Sopenharmony_ci eu = 0; 18168c2ecf20Sopenharmony_ci } else if (*str == 'k') { 18178c2ecf20Sopenharmony_ci if (!exclude) 18188c2ecf20Sopenharmony_ci exclude = eu = ek = eh = 1; 18198c2ecf20Sopenharmony_ci ek = 0; 18208c2ecf20Sopenharmony_ci } else if (*str == 'h') { 18218c2ecf20Sopenharmony_ci if (!exclude) 18228c2ecf20Sopenharmony_ci exclude = eu = ek = eh = 1; 18238c2ecf20Sopenharmony_ci eh = 0; 18248c2ecf20Sopenharmony_ci } else if (*str == 'G') { 18258c2ecf20Sopenharmony_ci if (!exclude_GH) 18268c2ecf20Sopenharmony_ci exclude_GH = eG = eH = 1; 18278c2ecf20Sopenharmony_ci eG = 0; 18288c2ecf20Sopenharmony_ci } else if (*str == 'H') { 18298c2ecf20Sopenharmony_ci if (!exclude_GH) 18308c2ecf20Sopenharmony_ci exclude_GH = eG = eH = 1; 18318c2ecf20Sopenharmony_ci eH = 0; 18328c2ecf20Sopenharmony_ci } else if (*str == 'I') { 18338c2ecf20Sopenharmony_ci eI = 1; 18348c2ecf20Sopenharmony_ci } else if (*str == 'p') { 18358c2ecf20Sopenharmony_ci precise++; 18368c2ecf20Sopenharmony_ci /* use of precise requires exclude_guest */ 18378c2ecf20Sopenharmony_ci if (!exclude_GH) 18388c2ecf20Sopenharmony_ci eG = 1; 18398c2ecf20Sopenharmony_ci } else if (*str == 'P') { 18408c2ecf20Sopenharmony_ci precise_max = 1; 18418c2ecf20Sopenharmony_ci } else if (*str == 'S') { 18428c2ecf20Sopenharmony_ci sample_read = 1; 18438c2ecf20Sopenharmony_ci } else if (*str == 'D') { 18448c2ecf20Sopenharmony_ci pinned = 1; 18458c2ecf20Sopenharmony_ci } else if (*str == 'e') { 18468c2ecf20Sopenharmony_ci exclusive = 1; 18478c2ecf20Sopenharmony_ci } else if (*str == 'W') { 18488c2ecf20Sopenharmony_ci weak = 1; 18498c2ecf20Sopenharmony_ci } else 18508c2ecf20Sopenharmony_ci break; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci ++str; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* 18568c2ecf20Sopenharmony_ci * precise ip: 18578c2ecf20Sopenharmony_ci * 18588c2ecf20Sopenharmony_ci * 0 - SAMPLE_IP can have arbitrary skid 18598c2ecf20Sopenharmony_ci * 1 - SAMPLE_IP must have constant skid 18608c2ecf20Sopenharmony_ci * 2 - SAMPLE_IP requested to have 0 skid 18618c2ecf20Sopenharmony_ci * 3 - SAMPLE_IP must have 0 skid 18628c2ecf20Sopenharmony_ci * 18638c2ecf20Sopenharmony_ci * See also PERF_RECORD_MISC_EXACT_IP 18648c2ecf20Sopenharmony_ci */ 18658c2ecf20Sopenharmony_ci if (precise > 3) 18668c2ecf20Sopenharmony_ci return -EINVAL; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci mod->eu = eu; 18698c2ecf20Sopenharmony_ci mod->ek = ek; 18708c2ecf20Sopenharmony_ci mod->eh = eh; 18718c2ecf20Sopenharmony_ci mod->eH = eH; 18728c2ecf20Sopenharmony_ci mod->eG = eG; 18738c2ecf20Sopenharmony_ci mod->eI = eI; 18748c2ecf20Sopenharmony_ci mod->precise = precise; 18758c2ecf20Sopenharmony_ci mod->precise_max = precise_max; 18768c2ecf20Sopenharmony_ci mod->exclude_GH = exclude_GH; 18778c2ecf20Sopenharmony_ci mod->sample_read = sample_read; 18788c2ecf20Sopenharmony_ci mod->pinned = pinned; 18798c2ecf20Sopenharmony_ci mod->weak = weak; 18808c2ecf20Sopenharmony_ci mod->exclusive = exclusive; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci return 0; 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci/* 18868c2ecf20Sopenharmony_ci * Basic modifier sanity check to validate it contains only one 18878c2ecf20Sopenharmony_ci * instance of any modifier (apart from 'p') present. 18888c2ecf20Sopenharmony_ci */ 18898c2ecf20Sopenharmony_cistatic int check_modifier(char *str) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci char *p = str; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* The sizeof includes 0 byte as well. */ 18948c2ecf20Sopenharmony_ci if (strlen(str) > (sizeof("ukhGHpppPSDIWe") - 1)) 18958c2ecf20Sopenharmony_ci return -1; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci while (*p) { 18988c2ecf20Sopenharmony_ci if (*p != 'p' && strchr(p + 1, *p)) 18998c2ecf20Sopenharmony_ci return -1; 19008c2ecf20Sopenharmony_ci p++; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci return 0; 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ciint parse_events__modifier_event(struct list_head *list, char *str, bool add) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci struct evsel *evsel; 19098c2ecf20Sopenharmony_ci struct event_modifier mod; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci if (str == NULL) 19128c2ecf20Sopenharmony_ci return 0; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (check_modifier(str)) 19158c2ecf20Sopenharmony_ci return -EINVAL; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci if (!add && get_event_modifier(&mod, str, NULL)) 19188c2ecf20Sopenharmony_ci return -EINVAL; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci __evlist__for_each_entry(list, evsel) { 19218c2ecf20Sopenharmony_ci if (add && get_event_modifier(&mod, str, evsel)) 19228c2ecf20Sopenharmony_ci return -EINVAL; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci evsel->core.attr.exclude_user = mod.eu; 19258c2ecf20Sopenharmony_ci evsel->core.attr.exclude_kernel = mod.ek; 19268c2ecf20Sopenharmony_ci evsel->core.attr.exclude_hv = mod.eh; 19278c2ecf20Sopenharmony_ci evsel->core.attr.precise_ip = mod.precise; 19288c2ecf20Sopenharmony_ci evsel->core.attr.exclude_host = mod.eH; 19298c2ecf20Sopenharmony_ci evsel->core.attr.exclude_guest = mod.eG; 19308c2ecf20Sopenharmony_ci evsel->core.attr.exclude_idle = mod.eI; 19318c2ecf20Sopenharmony_ci evsel->exclude_GH = mod.exclude_GH; 19328c2ecf20Sopenharmony_ci evsel->sample_read = mod.sample_read; 19338c2ecf20Sopenharmony_ci evsel->precise_max = mod.precise_max; 19348c2ecf20Sopenharmony_ci evsel->weak_group = mod.weak; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (evsel__is_group_leader(evsel)) { 19378c2ecf20Sopenharmony_ci evsel->core.attr.pinned = mod.pinned; 19388c2ecf20Sopenharmony_ci evsel->core.attr.exclusive = mod.exclusive; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci return 0; 19438c2ecf20Sopenharmony_ci} 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ciint parse_events_name(struct list_head *list, char *name) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci struct evsel *evsel; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci __evlist__for_each_entry(list, evsel) { 19508c2ecf20Sopenharmony_ci if (!evsel->name) 19518c2ecf20Sopenharmony_ci evsel->name = strdup(name); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci return 0; 19558c2ecf20Sopenharmony_ci} 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_cistatic int 19588c2ecf20Sopenharmony_cicomp_pmu(const void *p1, const void *p2) 19598c2ecf20Sopenharmony_ci{ 19608c2ecf20Sopenharmony_ci struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1; 19618c2ecf20Sopenharmony_ci struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci return strcasecmp(pmu1->symbol, pmu2->symbol); 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic void perf_pmu__parse_cleanup(void) 19678c2ecf20Sopenharmony_ci{ 19688c2ecf20Sopenharmony_ci if (perf_pmu_events_list_num > 0) { 19698c2ecf20Sopenharmony_ci struct perf_pmu_event_symbol *p; 19708c2ecf20Sopenharmony_ci int i; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci for (i = 0; i < perf_pmu_events_list_num; i++) { 19738c2ecf20Sopenharmony_ci p = perf_pmu_events_list + i; 19748c2ecf20Sopenharmony_ci zfree(&p->symbol); 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci zfree(&perf_pmu_events_list); 19778c2ecf20Sopenharmony_ci perf_pmu_events_list_num = 0; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci} 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci#define SET_SYMBOL(str, stype) \ 19828c2ecf20Sopenharmony_cido { \ 19838c2ecf20Sopenharmony_ci p->symbol = str; \ 19848c2ecf20Sopenharmony_ci if (!p->symbol) \ 19858c2ecf20Sopenharmony_ci goto err; \ 19868c2ecf20Sopenharmony_ci p->type = stype; \ 19878c2ecf20Sopenharmony_ci} while (0) 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci/* 19908c2ecf20Sopenharmony_ci * Read the pmu events list from sysfs 19918c2ecf20Sopenharmony_ci * Save it into perf_pmu_events_list 19928c2ecf20Sopenharmony_ci */ 19938c2ecf20Sopenharmony_cistatic void perf_pmu__parse_init(void) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci struct perf_pmu *pmu = NULL; 19978c2ecf20Sopenharmony_ci struct perf_pmu_alias *alias; 19988c2ecf20Sopenharmony_ci int len = 0; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci pmu = NULL; 20018c2ecf20Sopenharmony_ci while ((pmu = perf_pmu__scan(pmu)) != NULL) { 20028c2ecf20Sopenharmony_ci list_for_each_entry(alias, &pmu->aliases, list) { 20038c2ecf20Sopenharmony_ci if (strchr(alias->name, '-')) 20048c2ecf20Sopenharmony_ci len++; 20058c2ecf20Sopenharmony_ci len++; 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if (len == 0) { 20108c2ecf20Sopenharmony_ci perf_pmu_events_list_num = -1; 20118c2ecf20Sopenharmony_ci return; 20128c2ecf20Sopenharmony_ci } 20138c2ecf20Sopenharmony_ci perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len); 20148c2ecf20Sopenharmony_ci if (!perf_pmu_events_list) 20158c2ecf20Sopenharmony_ci return; 20168c2ecf20Sopenharmony_ci perf_pmu_events_list_num = len; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci len = 0; 20198c2ecf20Sopenharmony_ci pmu = NULL; 20208c2ecf20Sopenharmony_ci while ((pmu = perf_pmu__scan(pmu)) != NULL) { 20218c2ecf20Sopenharmony_ci list_for_each_entry(alias, &pmu->aliases, list) { 20228c2ecf20Sopenharmony_ci struct perf_pmu_event_symbol *p = perf_pmu_events_list + len; 20238c2ecf20Sopenharmony_ci char *tmp = strchr(alias->name, '-'); 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci if (tmp != NULL) { 20268c2ecf20Sopenharmony_ci SET_SYMBOL(strndup(alias->name, tmp - alias->name), 20278c2ecf20Sopenharmony_ci PMU_EVENT_SYMBOL_PREFIX); 20288c2ecf20Sopenharmony_ci p++; 20298c2ecf20Sopenharmony_ci SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX); 20308c2ecf20Sopenharmony_ci len += 2; 20318c2ecf20Sopenharmony_ci } else { 20328c2ecf20Sopenharmony_ci SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL); 20338c2ecf20Sopenharmony_ci len++; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci qsort(perf_pmu_events_list, len, 20388c2ecf20Sopenharmony_ci sizeof(struct perf_pmu_event_symbol), comp_pmu); 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci return; 20418c2ecf20Sopenharmony_cierr: 20428c2ecf20Sopenharmony_ci perf_pmu__parse_cleanup(); 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci/* 20468c2ecf20Sopenharmony_ci * This function injects special term in 20478c2ecf20Sopenharmony_ci * perf_pmu_events_list so the test code 20488c2ecf20Sopenharmony_ci * can check on this functionality. 20498c2ecf20Sopenharmony_ci */ 20508c2ecf20Sopenharmony_ciint perf_pmu__test_parse_init(void) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct perf_pmu_event_symbol *list; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci list = malloc(sizeof(*list) * 1); 20558c2ecf20Sopenharmony_ci if (!list) 20568c2ecf20Sopenharmony_ci return -ENOMEM; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci list->type = PMU_EVENT_SYMBOL; 20598c2ecf20Sopenharmony_ci list->symbol = strdup("read"); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci if (!list->symbol) { 20628c2ecf20Sopenharmony_ci free(list); 20638c2ecf20Sopenharmony_ci return -ENOMEM; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci perf_pmu_events_list = list; 20678c2ecf20Sopenharmony_ci perf_pmu_events_list_num = 1; 20688c2ecf20Sopenharmony_ci return 0; 20698c2ecf20Sopenharmony_ci} 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_cienum perf_pmu_event_symbol_type 20728c2ecf20Sopenharmony_ciperf_pmu__parse_check(const char *name) 20738c2ecf20Sopenharmony_ci{ 20748c2ecf20Sopenharmony_ci struct perf_pmu_event_symbol p, *r; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci /* scan kernel pmu events from sysfs if needed */ 20778c2ecf20Sopenharmony_ci if (perf_pmu_events_list_num == 0) 20788c2ecf20Sopenharmony_ci perf_pmu__parse_init(); 20798c2ecf20Sopenharmony_ci /* 20808c2ecf20Sopenharmony_ci * name "cpu" could be prefix of cpu-cycles or cpu// events. 20818c2ecf20Sopenharmony_ci * cpu-cycles has been handled by hardcode. 20828c2ecf20Sopenharmony_ci * So it must be cpu// events, not kernel pmu event. 20838c2ecf20Sopenharmony_ci */ 20848c2ecf20Sopenharmony_ci if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu")) 20858c2ecf20Sopenharmony_ci return PMU_EVENT_SYMBOL_ERR; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci p.symbol = strdup(name); 20888c2ecf20Sopenharmony_ci r = bsearch(&p, perf_pmu_events_list, 20898c2ecf20Sopenharmony_ci (size_t) perf_pmu_events_list_num, 20908c2ecf20Sopenharmony_ci sizeof(struct perf_pmu_event_symbol), comp_pmu); 20918c2ecf20Sopenharmony_ci zfree(&p.symbol); 20928c2ecf20Sopenharmony_ci return r ? r->type : PMU_EVENT_SYMBOL_ERR; 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int parse_events__scanner(const char *str, 20968c2ecf20Sopenharmony_ci struct parse_events_state *parse_state) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci YY_BUFFER_STATE buffer; 20998c2ecf20Sopenharmony_ci void *scanner; 21008c2ecf20Sopenharmony_ci int ret; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci ret = parse_events_lex_init_extra(parse_state, &scanner); 21038c2ecf20Sopenharmony_ci if (ret) 21048c2ecf20Sopenharmony_ci return ret; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci buffer = parse_events__scan_string(str, scanner); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci#ifdef PARSER_DEBUG 21098c2ecf20Sopenharmony_ci parse_events_debug = 1; 21108c2ecf20Sopenharmony_ci parse_events_set_debug(1, scanner); 21118c2ecf20Sopenharmony_ci#endif 21128c2ecf20Sopenharmony_ci ret = parse_events_parse(parse_state, scanner); 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci parse_events__flush_buffer(buffer, scanner); 21158c2ecf20Sopenharmony_ci parse_events__delete_buffer(buffer, scanner); 21168c2ecf20Sopenharmony_ci parse_events_lex_destroy(scanner); 21178c2ecf20Sopenharmony_ci return ret; 21188c2ecf20Sopenharmony_ci} 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci/* 21218c2ecf20Sopenharmony_ci * parse event config string, return a list of event terms. 21228c2ecf20Sopenharmony_ci */ 21238c2ecf20Sopenharmony_ciint parse_events_terms(struct list_head *terms, const char *str) 21248c2ecf20Sopenharmony_ci{ 21258c2ecf20Sopenharmony_ci struct parse_events_state parse_state = { 21268c2ecf20Sopenharmony_ci .terms = NULL, 21278c2ecf20Sopenharmony_ci .stoken = PE_START_TERMS, 21288c2ecf20Sopenharmony_ci }; 21298c2ecf20Sopenharmony_ci int ret; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci ret = parse_events__scanner(str, &parse_state); 21328c2ecf20Sopenharmony_ci perf_pmu__parse_cleanup(); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (!ret) { 21358c2ecf20Sopenharmony_ci list_splice(parse_state.terms, terms); 21368c2ecf20Sopenharmony_ci zfree(&parse_state.terms); 21378c2ecf20Sopenharmony_ci return 0; 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci parse_events_terms__delete(parse_state.terms); 21418c2ecf20Sopenharmony_ci return ret; 21428c2ecf20Sopenharmony_ci} 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ciint __parse_events(struct evlist *evlist, const char *str, 21458c2ecf20Sopenharmony_ci struct parse_events_error *err, struct perf_pmu *fake_pmu) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci struct parse_events_state parse_state = { 21488c2ecf20Sopenharmony_ci .list = LIST_HEAD_INIT(parse_state.list), 21498c2ecf20Sopenharmony_ci .idx = evlist->core.nr_entries, 21508c2ecf20Sopenharmony_ci .error = err, 21518c2ecf20Sopenharmony_ci .evlist = evlist, 21528c2ecf20Sopenharmony_ci .stoken = PE_START_EVENTS, 21538c2ecf20Sopenharmony_ci .fake_pmu = fake_pmu, 21548c2ecf20Sopenharmony_ci }; 21558c2ecf20Sopenharmony_ci int ret; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci ret = parse_events__scanner(str, &parse_state); 21588c2ecf20Sopenharmony_ci perf_pmu__parse_cleanup(); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci if (!ret && list_empty(&parse_state.list)) { 21618c2ecf20Sopenharmony_ci WARN_ONCE(true, "WARNING: event parser found nothing\n"); 21628c2ecf20Sopenharmony_ci return -1; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci /* 21668c2ecf20Sopenharmony_ci * Add list to the evlist even with errors to allow callers to clean up. 21678c2ecf20Sopenharmony_ci */ 21688c2ecf20Sopenharmony_ci perf_evlist__splice_list_tail(evlist, &parse_state.list); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci if (!ret) { 21718c2ecf20Sopenharmony_ci struct evsel *last; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci evlist->nr_groups += parse_state.nr_groups; 21748c2ecf20Sopenharmony_ci last = evlist__last(evlist); 21758c2ecf20Sopenharmony_ci last->cmdline_group_boundary = true; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci return 0; 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* 21818c2ecf20Sopenharmony_ci * There are 2 users - builtin-record and builtin-test objects. 21828c2ecf20Sopenharmony_ci * Both call evlist__delete in case of error, so we dont 21838c2ecf20Sopenharmony_ci * need to bother. 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_ci return ret; 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci#define MAX_WIDTH 1000 21898c2ecf20Sopenharmony_cistatic int get_term_width(void) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci struct winsize ws; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci get_term_dimensions(&ws); 21948c2ecf20Sopenharmony_ci return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col; 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic void __parse_events_print_error(int err_idx, const char *err_str, 21988c2ecf20Sopenharmony_ci const char *err_help, const char *event) 21998c2ecf20Sopenharmony_ci{ 22008c2ecf20Sopenharmony_ci const char *str = "invalid or unsupported event: "; 22018c2ecf20Sopenharmony_ci char _buf[MAX_WIDTH]; 22028c2ecf20Sopenharmony_ci char *buf = (char *) event; 22038c2ecf20Sopenharmony_ci int idx = 0; 22048c2ecf20Sopenharmony_ci if (err_str) { 22058c2ecf20Sopenharmony_ci /* -2 for extra '' in the final fprintf */ 22068c2ecf20Sopenharmony_ci int width = get_term_width() - 2; 22078c2ecf20Sopenharmony_ci int len_event = strlen(event); 22088c2ecf20Sopenharmony_ci int len_str, max_len, cut = 0; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci /* 22118c2ecf20Sopenharmony_ci * Maximum error index indent, we will cut 22128c2ecf20Sopenharmony_ci * the event string if it's bigger. 22138c2ecf20Sopenharmony_ci */ 22148c2ecf20Sopenharmony_ci int max_err_idx = 13; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci /* 22178c2ecf20Sopenharmony_ci * Let's be specific with the message when 22188c2ecf20Sopenharmony_ci * we have the precise error. 22198c2ecf20Sopenharmony_ci */ 22208c2ecf20Sopenharmony_ci str = "event syntax error: "; 22218c2ecf20Sopenharmony_ci len_str = strlen(str); 22228c2ecf20Sopenharmony_ci max_len = width - len_str; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci buf = _buf; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci /* We're cutting from the beginning. */ 22278c2ecf20Sopenharmony_ci if (err_idx > max_err_idx) 22288c2ecf20Sopenharmony_ci cut = err_idx - max_err_idx; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci strncpy(buf, event + cut, max_len); 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* Mark cut parts with '..' on both sides. */ 22338c2ecf20Sopenharmony_ci if (cut) 22348c2ecf20Sopenharmony_ci buf[0] = buf[1] = '.'; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci if ((len_event - cut) > max_len) { 22378c2ecf20Sopenharmony_ci buf[max_len - 1] = buf[max_len - 2] = '.'; 22388c2ecf20Sopenharmony_ci buf[max_len] = 0; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci idx = len_str + err_idx - cut; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci fprintf(stderr, "%s'%s'\n", str, buf); 22458c2ecf20Sopenharmony_ci if (idx) { 22468c2ecf20Sopenharmony_ci fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err_str); 22478c2ecf20Sopenharmony_ci if (err_help) 22488c2ecf20Sopenharmony_ci fprintf(stderr, "\n%s\n", err_help); 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci} 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_civoid parse_events_print_error(struct parse_events_error *err, 22538c2ecf20Sopenharmony_ci const char *event) 22548c2ecf20Sopenharmony_ci{ 22558c2ecf20Sopenharmony_ci if (!err->num_errors) 22568c2ecf20Sopenharmony_ci return; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci __parse_events_print_error(err->idx, err->str, err->help, event); 22598c2ecf20Sopenharmony_ci zfree(&err->str); 22608c2ecf20Sopenharmony_ci zfree(&err->help); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci if (err->num_errors > 1) { 22638c2ecf20Sopenharmony_ci fputs("\nInitial error:\n", stderr); 22648c2ecf20Sopenharmony_ci __parse_events_print_error(err->first_idx, err->first_str, 22658c2ecf20Sopenharmony_ci err->first_help, event); 22668c2ecf20Sopenharmony_ci zfree(&err->first_str); 22678c2ecf20Sopenharmony_ci zfree(&err->first_help); 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci} 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci#undef MAX_WIDTH 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ciint parse_events_option(const struct option *opt, const char *str, 22748c2ecf20Sopenharmony_ci int unset __maybe_unused) 22758c2ecf20Sopenharmony_ci{ 22768c2ecf20Sopenharmony_ci struct evlist *evlist = *(struct evlist **)opt->value; 22778c2ecf20Sopenharmony_ci struct parse_events_error err; 22788c2ecf20Sopenharmony_ci int ret; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci bzero(&err, sizeof(err)); 22818c2ecf20Sopenharmony_ci ret = parse_events(evlist, str, &err); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci if (ret) { 22848c2ecf20Sopenharmony_ci parse_events_print_error(&err, str); 22858c2ecf20Sopenharmony_ci fprintf(stderr, "Run 'perf list' for a list of valid events\n"); 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci return ret; 22898c2ecf20Sopenharmony_ci} 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ciint parse_events_option_new_evlist(const struct option *opt, const char *str, int unset) 22928c2ecf20Sopenharmony_ci{ 22938c2ecf20Sopenharmony_ci struct evlist **evlistp = opt->value; 22948c2ecf20Sopenharmony_ci int ret; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci if (*evlistp == NULL) { 22978c2ecf20Sopenharmony_ci *evlistp = evlist__new(); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (*evlistp == NULL) { 23008c2ecf20Sopenharmony_ci fprintf(stderr, "Not enough memory to create evlist\n"); 23018c2ecf20Sopenharmony_ci return -1; 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci ret = parse_events_option(opt, str, unset); 23068c2ecf20Sopenharmony_ci if (ret) { 23078c2ecf20Sopenharmony_ci evlist__delete(*evlistp); 23088c2ecf20Sopenharmony_ci *evlistp = NULL; 23098c2ecf20Sopenharmony_ci } 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci return ret; 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_cistatic int 23158c2ecf20Sopenharmony_ciforeach_evsel_in_last_glob(struct evlist *evlist, 23168c2ecf20Sopenharmony_ci int (*func)(struct evsel *evsel, 23178c2ecf20Sopenharmony_ci const void *arg), 23188c2ecf20Sopenharmony_ci const void *arg) 23198c2ecf20Sopenharmony_ci{ 23208c2ecf20Sopenharmony_ci struct evsel *last = NULL; 23218c2ecf20Sopenharmony_ci int err; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci /* 23248c2ecf20Sopenharmony_ci * Don't return when list_empty, give func a chance to report 23258c2ecf20Sopenharmony_ci * error when it found last == NULL. 23268c2ecf20Sopenharmony_ci * 23278c2ecf20Sopenharmony_ci * So no need to WARN here, let *func do this. 23288c2ecf20Sopenharmony_ci */ 23298c2ecf20Sopenharmony_ci if (evlist->core.nr_entries > 0) 23308c2ecf20Sopenharmony_ci last = evlist__last(evlist); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci do { 23338c2ecf20Sopenharmony_ci err = (*func)(last, arg); 23348c2ecf20Sopenharmony_ci if (err) 23358c2ecf20Sopenharmony_ci return -1; 23368c2ecf20Sopenharmony_ci if (!last) 23378c2ecf20Sopenharmony_ci return 0; 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (last->core.node.prev == &evlist->core.entries) 23408c2ecf20Sopenharmony_ci return 0; 23418c2ecf20Sopenharmony_ci last = list_entry(last->core.node.prev, struct evsel, core.node); 23428c2ecf20Sopenharmony_ci } while (!last->cmdline_group_boundary); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci return 0; 23458c2ecf20Sopenharmony_ci} 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_cistatic int set_filter(struct evsel *evsel, const void *arg) 23488c2ecf20Sopenharmony_ci{ 23498c2ecf20Sopenharmony_ci const char *str = arg; 23508c2ecf20Sopenharmony_ci bool found = false; 23518c2ecf20Sopenharmony_ci int nr_addr_filters = 0; 23528c2ecf20Sopenharmony_ci struct perf_pmu *pmu = NULL; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci if (evsel == NULL) { 23558c2ecf20Sopenharmony_ci fprintf(stderr, 23568c2ecf20Sopenharmony_ci "--filter option should follow a -e tracepoint or HW tracer option\n"); 23578c2ecf20Sopenharmony_ci return -1; 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { 23618c2ecf20Sopenharmony_ci if (evsel__append_tp_filter(evsel, str) < 0) { 23628c2ecf20Sopenharmony_ci fprintf(stderr, 23638c2ecf20Sopenharmony_ci "not enough memory to hold filter string\n"); 23648c2ecf20Sopenharmony_ci return -1; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci return 0; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci while ((pmu = perf_pmu__scan(pmu)) != NULL) 23718c2ecf20Sopenharmony_ci if (pmu->type == evsel->core.attr.type) { 23728c2ecf20Sopenharmony_ci found = true; 23738c2ecf20Sopenharmony_ci break; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (found) 23778c2ecf20Sopenharmony_ci perf_pmu__scan_file(pmu, "nr_addr_filters", 23788c2ecf20Sopenharmony_ci "%d", &nr_addr_filters); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci if (!nr_addr_filters) { 23818c2ecf20Sopenharmony_ci fprintf(stderr, 23828c2ecf20Sopenharmony_ci "This CPU does not support address filtering\n"); 23838c2ecf20Sopenharmony_ci return -1; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci if (evsel__append_addr_filter(evsel, str) < 0) { 23878c2ecf20Sopenharmony_ci fprintf(stderr, 23888c2ecf20Sopenharmony_ci "not enough memory to hold filter string\n"); 23898c2ecf20Sopenharmony_ci return -1; 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci return 0; 23938c2ecf20Sopenharmony_ci} 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ciint parse_filter(const struct option *opt, const char *str, 23968c2ecf20Sopenharmony_ci int unset __maybe_unused) 23978c2ecf20Sopenharmony_ci{ 23988c2ecf20Sopenharmony_ci struct evlist *evlist = *(struct evlist **)opt->value; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci return foreach_evsel_in_last_glob(evlist, set_filter, 24018c2ecf20Sopenharmony_ci (const void *)str); 24028c2ecf20Sopenharmony_ci} 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_cistatic int add_exclude_perf_filter(struct evsel *evsel, 24058c2ecf20Sopenharmony_ci const void *arg __maybe_unused) 24068c2ecf20Sopenharmony_ci{ 24078c2ecf20Sopenharmony_ci char new_filter[64]; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci if (evsel == NULL || evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { 24108c2ecf20Sopenharmony_ci fprintf(stderr, 24118c2ecf20Sopenharmony_ci "--exclude-perf option should follow a -e tracepoint option\n"); 24128c2ecf20Sopenharmony_ci return -1; 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid()); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci if (evsel__append_tp_filter(evsel, new_filter) < 0) { 24188c2ecf20Sopenharmony_ci fprintf(stderr, 24198c2ecf20Sopenharmony_ci "not enough memory to hold filter string\n"); 24208c2ecf20Sopenharmony_ci return -1; 24218c2ecf20Sopenharmony_ci } 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci return 0; 24248c2ecf20Sopenharmony_ci} 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ciint exclude_perf(const struct option *opt, 24278c2ecf20Sopenharmony_ci const char *arg __maybe_unused, 24288c2ecf20Sopenharmony_ci int unset __maybe_unused) 24298c2ecf20Sopenharmony_ci{ 24308c2ecf20Sopenharmony_ci struct evlist *evlist = *(struct evlist **)opt->value; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, 24338c2ecf20Sopenharmony_ci NULL); 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_cistatic const char * const event_type_descriptors[] = { 24378c2ecf20Sopenharmony_ci "Hardware event", 24388c2ecf20Sopenharmony_ci "Software event", 24398c2ecf20Sopenharmony_ci "Tracepoint event", 24408c2ecf20Sopenharmony_ci "Hardware cache event", 24418c2ecf20Sopenharmony_ci "Raw hardware event descriptor", 24428c2ecf20Sopenharmony_ci "Hardware breakpoint", 24438c2ecf20Sopenharmony_ci}; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_cistatic int cmp_string(const void *a, const void *b) 24468c2ecf20Sopenharmony_ci{ 24478c2ecf20Sopenharmony_ci const char * const *as = a; 24488c2ecf20Sopenharmony_ci const char * const *bs = b; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci return strcmp(*as, *bs); 24518c2ecf20Sopenharmony_ci} 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci/* 24548c2ecf20Sopenharmony_ci * Print the events from <debugfs_mount_point>/tracing/events 24558c2ecf20Sopenharmony_ci */ 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_civoid print_tracepoint_events(const char *subsys_glob, const char *event_glob, 24588c2ecf20Sopenharmony_ci bool name_only) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci DIR *sys_dir, *evt_dir; 24618c2ecf20Sopenharmony_ci struct dirent *sys_dirent, *evt_dirent; 24628c2ecf20Sopenharmony_ci char evt_path[MAXPATHLEN]; 24638c2ecf20Sopenharmony_ci char *dir_path; 24648c2ecf20Sopenharmony_ci char **evt_list = NULL; 24658c2ecf20Sopenharmony_ci unsigned int evt_i = 0, evt_num = 0; 24668c2ecf20Sopenharmony_ci bool evt_num_known = false; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_cirestart: 24698c2ecf20Sopenharmony_ci sys_dir = tracing_events__opendir(); 24708c2ecf20Sopenharmony_ci if (!sys_dir) 24718c2ecf20Sopenharmony_ci return; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (evt_num_known) { 24748c2ecf20Sopenharmony_ci evt_list = zalloc(sizeof(char *) * evt_num); 24758c2ecf20Sopenharmony_ci if (!evt_list) 24768c2ecf20Sopenharmony_ci goto out_close_sys_dir; 24778c2ecf20Sopenharmony_ci } 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci for_each_subsystem(sys_dir, sys_dirent) { 24808c2ecf20Sopenharmony_ci if (subsys_glob != NULL && 24818c2ecf20Sopenharmony_ci !strglobmatch(sys_dirent->d_name, subsys_glob)) 24828c2ecf20Sopenharmony_ci continue; 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci dir_path = get_events_file(sys_dirent->d_name); 24858c2ecf20Sopenharmony_ci if (!dir_path) 24868c2ecf20Sopenharmony_ci continue; 24878c2ecf20Sopenharmony_ci evt_dir = opendir(dir_path); 24888c2ecf20Sopenharmony_ci if (!evt_dir) 24898c2ecf20Sopenharmony_ci goto next; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci for_each_event(dir_path, evt_dir, evt_dirent) { 24928c2ecf20Sopenharmony_ci if (event_glob != NULL && 24938c2ecf20Sopenharmony_ci !strglobmatch(evt_dirent->d_name, event_glob)) 24948c2ecf20Sopenharmony_ci continue; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci if (!evt_num_known) { 24978c2ecf20Sopenharmony_ci evt_num++; 24988c2ecf20Sopenharmony_ci continue; 24998c2ecf20Sopenharmony_ci } 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci snprintf(evt_path, MAXPATHLEN, "%s:%s", 25028c2ecf20Sopenharmony_ci sys_dirent->d_name, evt_dirent->d_name); 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci evt_list[evt_i] = strdup(evt_path); 25058c2ecf20Sopenharmony_ci if (evt_list[evt_i] == NULL) { 25068c2ecf20Sopenharmony_ci put_events_file(dir_path); 25078c2ecf20Sopenharmony_ci goto out_close_evt_dir; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci evt_i++; 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci closedir(evt_dir); 25128c2ecf20Sopenharmony_cinext: 25138c2ecf20Sopenharmony_ci put_events_file(dir_path); 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci closedir(sys_dir); 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci if (!evt_num_known) { 25188c2ecf20Sopenharmony_ci evt_num_known = true; 25198c2ecf20Sopenharmony_ci goto restart; 25208c2ecf20Sopenharmony_ci } 25218c2ecf20Sopenharmony_ci qsort(evt_list, evt_num, sizeof(char *), cmp_string); 25228c2ecf20Sopenharmony_ci evt_i = 0; 25238c2ecf20Sopenharmony_ci while (evt_i < evt_num) { 25248c2ecf20Sopenharmony_ci if (name_only) { 25258c2ecf20Sopenharmony_ci printf("%s ", evt_list[evt_i++]); 25268c2ecf20Sopenharmony_ci continue; 25278c2ecf20Sopenharmony_ci } 25288c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", evt_list[evt_i++], 25298c2ecf20Sopenharmony_ci event_type_descriptors[PERF_TYPE_TRACEPOINT]); 25308c2ecf20Sopenharmony_ci } 25318c2ecf20Sopenharmony_ci if (evt_num && pager_in_use()) 25328c2ecf20Sopenharmony_ci printf("\n"); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ciout_free: 25358c2ecf20Sopenharmony_ci evt_num = evt_i; 25368c2ecf20Sopenharmony_ci for (evt_i = 0; evt_i < evt_num; evt_i++) 25378c2ecf20Sopenharmony_ci zfree(&evt_list[evt_i]); 25388c2ecf20Sopenharmony_ci zfree(&evt_list); 25398c2ecf20Sopenharmony_ci return; 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ciout_close_evt_dir: 25428c2ecf20Sopenharmony_ci closedir(evt_dir); 25438c2ecf20Sopenharmony_ciout_close_sys_dir: 25448c2ecf20Sopenharmony_ci closedir(sys_dir); 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci printf("FATAL: not enough memory to print %s\n", 25478c2ecf20Sopenharmony_ci event_type_descriptors[PERF_TYPE_TRACEPOINT]); 25488c2ecf20Sopenharmony_ci if (evt_list) 25498c2ecf20Sopenharmony_ci goto out_free; 25508c2ecf20Sopenharmony_ci} 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci/* 25538c2ecf20Sopenharmony_ci * Check whether event is in <debugfs_mount_point>/tracing/events 25548c2ecf20Sopenharmony_ci */ 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ciint is_valid_tracepoint(const char *event_string) 25578c2ecf20Sopenharmony_ci{ 25588c2ecf20Sopenharmony_ci DIR *sys_dir, *evt_dir; 25598c2ecf20Sopenharmony_ci struct dirent *sys_dirent, *evt_dirent; 25608c2ecf20Sopenharmony_ci char evt_path[MAXPATHLEN]; 25618c2ecf20Sopenharmony_ci char *dir_path; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci sys_dir = tracing_events__opendir(); 25648c2ecf20Sopenharmony_ci if (!sys_dir) 25658c2ecf20Sopenharmony_ci return 0; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci for_each_subsystem(sys_dir, sys_dirent) { 25688c2ecf20Sopenharmony_ci dir_path = get_events_file(sys_dirent->d_name); 25698c2ecf20Sopenharmony_ci if (!dir_path) 25708c2ecf20Sopenharmony_ci continue; 25718c2ecf20Sopenharmony_ci evt_dir = opendir(dir_path); 25728c2ecf20Sopenharmony_ci if (!evt_dir) 25738c2ecf20Sopenharmony_ci goto next; 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci for_each_event(dir_path, evt_dir, evt_dirent) { 25768c2ecf20Sopenharmony_ci snprintf(evt_path, MAXPATHLEN, "%s:%s", 25778c2ecf20Sopenharmony_ci sys_dirent->d_name, evt_dirent->d_name); 25788c2ecf20Sopenharmony_ci if (!strcmp(evt_path, event_string)) { 25798c2ecf20Sopenharmony_ci closedir(evt_dir); 25808c2ecf20Sopenharmony_ci closedir(sys_dir); 25818c2ecf20Sopenharmony_ci return 1; 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci closedir(evt_dir); 25858c2ecf20Sopenharmony_cinext: 25868c2ecf20Sopenharmony_ci put_events_file(dir_path); 25878c2ecf20Sopenharmony_ci } 25888c2ecf20Sopenharmony_ci closedir(sys_dir); 25898c2ecf20Sopenharmony_ci return 0; 25908c2ecf20Sopenharmony_ci} 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_cistatic bool is_event_supported(u8 type, unsigned config) 25938c2ecf20Sopenharmony_ci{ 25948c2ecf20Sopenharmony_ci bool ret = true; 25958c2ecf20Sopenharmony_ci int open_return; 25968c2ecf20Sopenharmony_ci struct evsel *evsel; 25978c2ecf20Sopenharmony_ci struct perf_event_attr attr = { 25988c2ecf20Sopenharmony_ci .type = type, 25998c2ecf20Sopenharmony_ci .config = config, 26008c2ecf20Sopenharmony_ci .disabled = 1, 26018c2ecf20Sopenharmony_ci }; 26028c2ecf20Sopenharmony_ci struct perf_thread_map *tmap = thread_map__new_by_tid(0); 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci if (tmap == NULL) 26058c2ecf20Sopenharmony_ci return false; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci evsel = evsel__new(&attr); 26088c2ecf20Sopenharmony_ci if (evsel) { 26098c2ecf20Sopenharmony_ci open_return = evsel__open(evsel, NULL, tmap); 26108c2ecf20Sopenharmony_ci ret = open_return >= 0; 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci if (open_return == -EACCES) { 26138c2ecf20Sopenharmony_ci /* 26148c2ecf20Sopenharmony_ci * This happens if the paranoid value 26158c2ecf20Sopenharmony_ci * /proc/sys/kernel/perf_event_paranoid is set to 2 26168c2ecf20Sopenharmony_ci * Re-run with exclude_kernel set; we don't do that 26178c2ecf20Sopenharmony_ci * by default as some ARM machines do not support it. 26188c2ecf20Sopenharmony_ci * 26198c2ecf20Sopenharmony_ci */ 26208c2ecf20Sopenharmony_ci evsel->core.attr.exclude_kernel = 1; 26218c2ecf20Sopenharmony_ci ret = evsel__open(evsel, NULL, tmap) >= 0; 26228c2ecf20Sopenharmony_ci } 26238c2ecf20Sopenharmony_ci evsel__delete(evsel); 26248c2ecf20Sopenharmony_ci } 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci perf_thread_map__put(tmap); 26278c2ecf20Sopenharmony_ci return ret; 26288c2ecf20Sopenharmony_ci} 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_civoid print_sdt_events(const char *subsys_glob, const char *event_glob, 26318c2ecf20Sopenharmony_ci bool name_only) 26328c2ecf20Sopenharmony_ci{ 26338c2ecf20Sopenharmony_ci struct probe_cache *pcache; 26348c2ecf20Sopenharmony_ci struct probe_cache_entry *ent; 26358c2ecf20Sopenharmony_ci struct strlist *bidlist, *sdtlist; 26368c2ecf20Sopenharmony_ci struct strlist_config cfg = {.dont_dupstr = true}; 26378c2ecf20Sopenharmony_ci struct str_node *nd, *nd2; 26388c2ecf20Sopenharmony_ci char *buf, *path, *ptr = NULL; 26398c2ecf20Sopenharmony_ci bool show_detail = false; 26408c2ecf20Sopenharmony_ci int ret; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci sdtlist = strlist__new(NULL, &cfg); 26438c2ecf20Sopenharmony_ci if (!sdtlist) { 26448c2ecf20Sopenharmony_ci pr_debug("Failed to allocate new strlist for SDT\n"); 26458c2ecf20Sopenharmony_ci return; 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci bidlist = build_id_cache__list_all(true); 26488c2ecf20Sopenharmony_ci if (!bidlist) { 26498c2ecf20Sopenharmony_ci pr_debug("Failed to get buildids: %d\n", errno); 26508c2ecf20Sopenharmony_ci return; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci strlist__for_each_entry(nd, bidlist) { 26538c2ecf20Sopenharmony_ci pcache = probe_cache__new(nd->s, NULL); 26548c2ecf20Sopenharmony_ci if (!pcache) 26558c2ecf20Sopenharmony_ci continue; 26568c2ecf20Sopenharmony_ci list_for_each_entry(ent, &pcache->entries, node) { 26578c2ecf20Sopenharmony_ci if (!ent->sdt) 26588c2ecf20Sopenharmony_ci continue; 26598c2ecf20Sopenharmony_ci if (subsys_glob && 26608c2ecf20Sopenharmony_ci !strglobmatch(ent->pev.group, subsys_glob)) 26618c2ecf20Sopenharmony_ci continue; 26628c2ecf20Sopenharmony_ci if (event_glob && 26638c2ecf20Sopenharmony_ci !strglobmatch(ent->pev.event, event_glob)) 26648c2ecf20Sopenharmony_ci continue; 26658c2ecf20Sopenharmony_ci ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, 26668c2ecf20Sopenharmony_ci ent->pev.event, nd->s); 26678c2ecf20Sopenharmony_ci if (ret > 0) 26688c2ecf20Sopenharmony_ci strlist__add(sdtlist, buf); 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci probe_cache__delete(pcache); 26718c2ecf20Sopenharmony_ci } 26728c2ecf20Sopenharmony_ci strlist__delete(bidlist); 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci strlist__for_each_entry(nd, sdtlist) { 26758c2ecf20Sopenharmony_ci buf = strchr(nd->s, '@'); 26768c2ecf20Sopenharmony_ci if (buf) 26778c2ecf20Sopenharmony_ci *(buf++) = '\0'; 26788c2ecf20Sopenharmony_ci if (name_only) { 26798c2ecf20Sopenharmony_ci printf("%s ", nd->s); 26808c2ecf20Sopenharmony_ci continue; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci nd2 = strlist__next(nd); 26838c2ecf20Sopenharmony_ci if (nd2) { 26848c2ecf20Sopenharmony_ci ptr = strchr(nd2->s, '@'); 26858c2ecf20Sopenharmony_ci if (ptr) 26868c2ecf20Sopenharmony_ci *ptr = '\0'; 26878c2ecf20Sopenharmony_ci if (strcmp(nd->s, nd2->s) == 0) 26888c2ecf20Sopenharmony_ci show_detail = true; 26898c2ecf20Sopenharmony_ci } 26908c2ecf20Sopenharmony_ci if (show_detail) { 26918c2ecf20Sopenharmony_ci path = build_id_cache__origname(buf); 26928c2ecf20Sopenharmony_ci ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); 26938c2ecf20Sopenharmony_ci if (ret > 0) { 26948c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", buf, "SDT event"); 26958c2ecf20Sopenharmony_ci free(buf); 26968c2ecf20Sopenharmony_ci } 26978c2ecf20Sopenharmony_ci free(path); 26988c2ecf20Sopenharmony_ci } else 26998c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", nd->s, "SDT event"); 27008c2ecf20Sopenharmony_ci if (nd2) { 27018c2ecf20Sopenharmony_ci if (strcmp(nd->s, nd2->s) != 0) 27028c2ecf20Sopenharmony_ci show_detail = false; 27038c2ecf20Sopenharmony_ci if (ptr) 27048c2ecf20Sopenharmony_ci *ptr = '@'; 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci strlist__delete(sdtlist); 27088c2ecf20Sopenharmony_ci} 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ciint print_hwcache_events(const char *event_glob, bool name_only) 27118c2ecf20Sopenharmony_ci{ 27128c2ecf20Sopenharmony_ci unsigned int type, op, i, evt_i = 0, evt_num = 0; 27138c2ecf20Sopenharmony_ci char name[64]; 27148c2ecf20Sopenharmony_ci char **evt_list = NULL; 27158c2ecf20Sopenharmony_ci bool evt_num_known = false; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_cirestart: 27188c2ecf20Sopenharmony_ci if (evt_num_known) { 27198c2ecf20Sopenharmony_ci evt_list = zalloc(sizeof(char *) * evt_num); 27208c2ecf20Sopenharmony_ci if (!evt_list) 27218c2ecf20Sopenharmony_ci goto out_enomem; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 27258c2ecf20Sopenharmony_ci for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 27268c2ecf20Sopenharmony_ci /* skip invalid cache type */ 27278c2ecf20Sopenharmony_ci if (!evsel__is_cache_op_valid(type, op)) 27288c2ecf20Sopenharmony_ci continue; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 27318c2ecf20Sopenharmony_ci __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); 27328c2ecf20Sopenharmony_ci if (event_glob != NULL && !strglobmatch(name, event_glob)) 27338c2ecf20Sopenharmony_ci continue; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci if (!is_event_supported(PERF_TYPE_HW_CACHE, 27368c2ecf20Sopenharmony_ci type | (op << 8) | (i << 16))) 27378c2ecf20Sopenharmony_ci continue; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (!evt_num_known) { 27408c2ecf20Sopenharmony_ci evt_num++; 27418c2ecf20Sopenharmony_ci continue; 27428c2ecf20Sopenharmony_ci } 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci evt_list[evt_i] = strdup(name); 27458c2ecf20Sopenharmony_ci if (evt_list[evt_i] == NULL) 27468c2ecf20Sopenharmony_ci goto out_enomem; 27478c2ecf20Sopenharmony_ci evt_i++; 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci } 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci if (!evt_num_known) { 27538c2ecf20Sopenharmony_ci evt_num_known = true; 27548c2ecf20Sopenharmony_ci goto restart; 27558c2ecf20Sopenharmony_ci } 27568c2ecf20Sopenharmony_ci qsort(evt_list, evt_num, sizeof(char *), cmp_string); 27578c2ecf20Sopenharmony_ci evt_i = 0; 27588c2ecf20Sopenharmony_ci while (evt_i < evt_num) { 27598c2ecf20Sopenharmony_ci if (name_only) { 27608c2ecf20Sopenharmony_ci printf("%s ", evt_list[evt_i++]); 27618c2ecf20Sopenharmony_ci continue; 27628c2ecf20Sopenharmony_ci } 27638c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", evt_list[evt_i++], 27648c2ecf20Sopenharmony_ci event_type_descriptors[PERF_TYPE_HW_CACHE]); 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci if (evt_num && pager_in_use()) 27678c2ecf20Sopenharmony_ci printf("\n"); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ciout_free: 27708c2ecf20Sopenharmony_ci evt_num = evt_i; 27718c2ecf20Sopenharmony_ci for (evt_i = 0; evt_i < evt_num; evt_i++) 27728c2ecf20Sopenharmony_ci zfree(&evt_list[evt_i]); 27738c2ecf20Sopenharmony_ci zfree(&evt_list); 27748c2ecf20Sopenharmony_ci return evt_num; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ciout_enomem: 27778c2ecf20Sopenharmony_ci printf("FATAL: not enough memory to print %s\n", event_type_descriptors[PERF_TYPE_HW_CACHE]); 27788c2ecf20Sopenharmony_ci if (evt_list) 27798c2ecf20Sopenharmony_ci goto out_free; 27808c2ecf20Sopenharmony_ci return evt_num; 27818c2ecf20Sopenharmony_ci} 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_cistatic void print_tool_event(const char *name, const char *event_glob, 27848c2ecf20Sopenharmony_ci bool name_only) 27858c2ecf20Sopenharmony_ci{ 27868c2ecf20Sopenharmony_ci if (event_glob && !strglobmatch(name, event_glob)) 27878c2ecf20Sopenharmony_ci return; 27888c2ecf20Sopenharmony_ci if (name_only) 27898c2ecf20Sopenharmony_ci printf("%s ", name); 27908c2ecf20Sopenharmony_ci else 27918c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", name, "Tool event"); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci} 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_civoid print_tool_events(const char *event_glob, bool name_only) 27968c2ecf20Sopenharmony_ci{ 27978c2ecf20Sopenharmony_ci print_tool_event("duration_time", event_glob, name_only); 27988c2ecf20Sopenharmony_ci if (pager_in_use()) 27998c2ecf20Sopenharmony_ci printf("\n"); 28008c2ecf20Sopenharmony_ci} 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_civoid print_symbol_events(const char *event_glob, unsigned type, 28038c2ecf20Sopenharmony_ci struct event_symbol *syms, unsigned max, 28048c2ecf20Sopenharmony_ci bool name_only) 28058c2ecf20Sopenharmony_ci{ 28068c2ecf20Sopenharmony_ci unsigned int i, evt_i = 0, evt_num = 0; 28078c2ecf20Sopenharmony_ci char name[MAX_NAME_LEN]; 28088c2ecf20Sopenharmony_ci char **evt_list = NULL; 28098c2ecf20Sopenharmony_ci bool evt_num_known = false; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_cirestart: 28128c2ecf20Sopenharmony_ci if (evt_num_known) { 28138c2ecf20Sopenharmony_ci evt_list = zalloc(sizeof(char *) * evt_num); 28148c2ecf20Sopenharmony_ci if (!evt_list) 28158c2ecf20Sopenharmony_ci goto out_enomem; 28168c2ecf20Sopenharmony_ci syms -= max; 28178c2ecf20Sopenharmony_ci } 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci for (i = 0; i < max; i++, syms++) { 28208c2ecf20Sopenharmony_ci /* 28218c2ecf20Sopenharmony_ci * New attr.config still not supported here, the latest 28228c2ecf20Sopenharmony_ci * example was PERF_COUNT_SW_CGROUP_SWITCHES 28238c2ecf20Sopenharmony_ci */ 28248c2ecf20Sopenharmony_ci if (syms->symbol == NULL) 28258c2ecf20Sopenharmony_ci continue; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci if (event_glob != NULL && !(strglobmatch(syms->symbol, event_glob) || 28288c2ecf20Sopenharmony_ci (syms->alias && strglobmatch(syms->alias, event_glob)))) 28298c2ecf20Sopenharmony_ci continue; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci if (!is_event_supported(type, i)) 28328c2ecf20Sopenharmony_ci continue; 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci if (!evt_num_known) { 28358c2ecf20Sopenharmony_ci evt_num++; 28368c2ecf20Sopenharmony_ci continue; 28378c2ecf20Sopenharmony_ci } 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci if (!name_only && strlen(syms->alias)) 28408c2ecf20Sopenharmony_ci snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 28418c2ecf20Sopenharmony_ci else 28428c2ecf20Sopenharmony_ci strlcpy(name, syms->symbol, MAX_NAME_LEN); 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci evt_list[evt_i] = strdup(name); 28458c2ecf20Sopenharmony_ci if (evt_list[evt_i] == NULL) 28468c2ecf20Sopenharmony_ci goto out_enomem; 28478c2ecf20Sopenharmony_ci evt_i++; 28488c2ecf20Sopenharmony_ci } 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci if (!evt_num_known) { 28518c2ecf20Sopenharmony_ci evt_num_known = true; 28528c2ecf20Sopenharmony_ci goto restart; 28538c2ecf20Sopenharmony_ci } 28548c2ecf20Sopenharmony_ci qsort(evt_list, evt_num, sizeof(char *), cmp_string); 28558c2ecf20Sopenharmony_ci evt_i = 0; 28568c2ecf20Sopenharmony_ci while (evt_i < evt_num) { 28578c2ecf20Sopenharmony_ci if (name_only) { 28588c2ecf20Sopenharmony_ci printf("%s ", evt_list[evt_i++]); 28598c2ecf20Sopenharmony_ci continue; 28608c2ecf20Sopenharmony_ci } 28618c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]); 28628c2ecf20Sopenharmony_ci } 28638c2ecf20Sopenharmony_ci if (evt_num && pager_in_use()) 28648c2ecf20Sopenharmony_ci printf("\n"); 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ciout_free: 28678c2ecf20Sopenharmony_ci evt_num = evt_i; 28688c2ecf20Sopenharmony_ci for (evt_i = 0; evt_i < evt_num; evt_i++) 28698c2ecf20Sopenharmony_ci zfree(&evt_list[evt_i]); 28708c2ecf20Sopenharmony_ci zfree(&evt_list); 28718c2ecf20Sopenharmony_ci return; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ciout_enomem: 28748c2ecf20Sopenharmony_ci printf("FATAL: not enough memory to print %s\n", event_type_descriptors[type]); 28758c2ecf20Sopenharmony_ci if (evt_list) 28768c2ecf20Sopenharmony_ci goto out_free; 28778c2ecf20Sopenharmony_ci} 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci/* 28808c2ecf20Sopenharmony_ci * Print the help text for the event symbols: 28818c2ecf20Sopenharmony_ci */ 28828c2ecf20Sopenharmony_civoid print_events(const char *event_glob, bool name_only, bool quiet_flag, 28838c2ecf20Sopenharmony_ci bool long_desc, bool details_flag, bool deprecated) 28848c2ecf20Sopenharmony_ci{ 28858c2ecf20Sopenharmony_ci print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 28868c2ecf20Sopenharmony_ci event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, 28898c2ecf20Sopenharmony_ci event_symbols_sw, PERF_COUNT_SW_MAX, name_only); 28908c2ecf20Sopenharmony_ci print_tool_events(event_glob, name_only); 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci print_hwcache_events(event_glob, name_only); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci print_pmu_events(event_glob, name_only, quiet_flag, long_desc, 28958c2ecf20Sopenharmony_ci details_flag, deprecated); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci if (event_glob != NULL) 28988c2ecf20Sopenharmony_ci return; 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci if (!name_only) { 29018c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", 29028c2ecf20Sopenharmony_ci "rNNN", 29038c2ecf20Sopenharmony_ci event_type_descriptors[PERF_TYPE_RAW]); 29048c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", 29058c2ecf20Sopenharmony_ci "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 29068c2ecf20Sopenharmony_ci event_type_descriptors[PERF_TYPE_RAW]); 29078c2ecf20Sopenharmony_ci if (pager_in_use()) 29088c2ecf20Sopenharmony_ci printf(" (see 'man perf-list' on how to encode it)\n\n"); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci printf(" %-50s [%s]\n", 29118c2ecf20Sopenharmony_ci "mem:<addr>[/len][:access]", 29128c2ecf20Sopenharmony_ci event_type_descriptors[PERF_TYPE_BREAKPOINT]); 29138c2ecf20Sopenharmony_ci if (pager_in_use()) 29148c2ecf20Sopenharmony_ci printf("\n"); 29158c2ecf20Sopenharmony_ci } 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci print_tracepoint_events(NULL, NULL, name_only); 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci print_sdt_events(NULL, NULL, name_only); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci metricgroup__print(true, true, NULL, name_only, details_flag); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci print_libpfm_events(name_only, long_desc); 29248c2ecf20Sopenharmony_ci} 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ciint parse_events__is_hardcoded_term(struct parse_events_term *term) 29278c2ecf20Sopenharmony_ci{ 29288c2ecf20Sopenharmony_ci return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; 29298c2ecf20Sopenharmony_ci} 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_cistatic int new_term(struct parse_events_term **_term, 29328c2ecf20Sopenharmony_ci struct parse_events_term *temp, 29338c2ecf20Sopenharmony_ci char *str, u64 num) 29348c2ecf20Sopenharmony_ci{ 29358c2ecf20Sopenharmony_ci struct parse_events_term *term; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci term = malloc(sizeof(*term)); 29388c2ecf20Sopenharmony_ci if (!term) 29398c2ecf20Sopenharmony_ci return -ENOMEM; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci *term = *temp; 29428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&term->list); 29438c2ecf20Sopenharmony_ci term->weak = false; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci switch (term->type_val) { 29468c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_NUM: 29478c2ecf20Sopenharmony_ci term->val.num = num; 29488c2ecf20Sopenharmony_ci break; 29498c2ecf20Sopenharmony_ci case PARSE_EVENTS__TERM_TYPE_STR: 29508c2ecf20Sopenharmony_ci term->val.str = str; 29518c2ecf20Sopenharmony_ci break; 29528c2ecf20Sopenharmony_ci default: 29538c2ecf20Sopenharmony_ci free(term); 29548c2ecf20Sopenharmony_ci return -EINVAL; 29558c2ecf20Sopenharmony_ci } 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci *_term = term; 29588c2ecf20Sopenharmony_ci return 0; 29598c2ecf20Sopenharmony_ci} 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ciint parse_events_term__num(struct parse_events_term **term, 29628c2ecf20Sopenharmony_ci int type_term, char *config, u64 num, 29638c2ecf20Sopenharmony_ci bool no_value, 29648c2ecf20Sopenharmony_ci void *loc_term_, void *loc_val_) 29658c2ecf20Sopenharmony_ci{ 29668c2ecf20Sopenharmony_ci YYLTYPE *loc_term = loc_term_; 29678c2ecf20Sopenharmony_ci YYLTYPE *loc_val = loc_val_; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci struct parse_events_term temp = { 29708c2ecf20Sopenharmony_ci .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 29718c2ecf20Sopenharmony_ci .type_term = type_term, 29728c2ecf20Sopenharmony_ci .config = config, 29738c2ecf20Sopenharmony_ci .no_value = no_value, 29748c2ecf20Sopenharmony_ci .err_term = loc_term ? loc_term->first_column : 0, 29758c2ecf20Sopenharmony_ci .err_val = loc_val ? loc_val->first_column : 0, 29768c2ecf20Sopenharmony_ci }; 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci return new_term(term, &temp, NULL, num); 29798c2ecf20Sopenharmony_ci} 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ciint parse_events_term__str(struct parse_events_term **term, 29828c2ecf20Sopenharmony_ci int type_term, char *config, char *str, 29838c2ecf20Sopenharmony_ci void *loc_term_, void *loc_val_) 29848c2ecf20Sopenharmony_ci{ 29858c2ecf20Sopenharmony_ci YYLTYPE *loc_term = loc_term_; 29868c2ecf20Sopenharmony_ci YYLTYPE *loc_val = loc_val_; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci struct parse_events_term temp = { 29898c2ecf20Sopenharmony_ci .type_val = PARSE_EVENTS__TERM_TYPE_STR, 29908c2ecf20Sopenharmony_ci .type_term = type_term, 29918c2ecf20Sopenharmony_ci .config = config, 29928c2ecf20Sopenharmony_ci .err_term = loc_term ? loc_term->first_column : 0, 29938c2ecf20Sopenharmony_ci .err_val = loc_val ? loc_val->first_column : 0, 29948c2ecf20Sopenharmony_ci }; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci return new_term(term, &temp, str, 0); 29978c2ecf20Sopenharmony_ci} 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ciint parse_events_term__sym_hw(struct parse_events_term **term, 30008c2ecf20Sopenharmony_ci char *config, unsigned idx) 30018c2ecf20Sopenharmony_ci{ 30028c2ecf20Sopenharmony_ci struct event_symbol *sym; 30038c2ecf20Sopenharmony_ci char *str; 30048c2ecf20Sopenharmony_ci struct parse_events_term temp = { 30058c2ecf20Sopenharmony_ci .type_val = PARSE_EVENTS__TERM_TYPE_STR, 30068c2ecf20Sopenharmony_ci .type_term = PARSE_EVENTS__TERM_TYPE_USER, 30078c2ecf20Sopenharmony_ci .config = config, 30088c2ecf20Sopenharmony_ci }; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci if (!temp.config) { 30118c2ecf20Sopenharmony_ci temp.config = strdup("event"); 30128c2ecf20Sopenharmony_ci if (!temp.config) 30138c2ecf20Sopenharmony_ci return -ENOMEM; 30148c2ecf20Sopenharmony_ci } 30158c2ecf20Sopenharmony_ci BUG_ON(idx >= PERF_COUNT_HW_MAX); 30168c2ecf20Sopenharmony_ci sym = &event_symbols_hw[idx]; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci str = strdup(sym->symbol); 30198c2ecf20Sopenharmony_ci if (!str) 30208c2ecf20Sopenharmony_ci return -ENOMEM; 30218c2ecf20Sopenharmony_ci return new_term(term, &temp, str, 0); 30228c2ecf20Sopenharmony_ci} 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ciint parse_events_term__clone(struct parse_events_term **new, 30258c2ecf20Sopenharmony_ci struct parse_events_term *term) 30268c2ecf20Sopenharmony_ci{ 30278c2ecf20Sopenharmony_ci char *str; 30288c2ecf20Sopenharmony_ci struct parse_events_term temp = { 30298c2ecf20Sopenharmony_ci .type_val = term->type_val, 30308c2ecf20Sopenharmony_ci .type_term = term->type_term, 30318c2ecf20Sopenharmony_ci .config = NULL, 30328c2ecf20Sopenharmony_ci .err_term = term->err_term, 30338c2ecf20Sopenharmony_ci .err_val = term->err_val, 30348c2ecf20Sopenharmony_ci }; 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci if (term->config) { 30378c2ecf20Sopenharmony_ci temp.config = strdup(term->config); 30388c2ecf20Sopenharmony_ci if (!temp.config) 30398c2ecf20Sopenharmony_ci return -ENOMEM; 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 30428c2ecf20Sopenharmony_ci return new_term(new, &temp, NULL, term->val.num); 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci str = strdup(term->val.str); 30458c2ecf20Sopenharmony_ci if (!str) 30468c2ecf20Sopenharmony_ci return -ENOMEM; 30478c2ecf20Sopenharmony_ci return new_term(new, &temp, str, 0); 30488c2ecf20Sopenharmony_ci} 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_civoid parse_events_term__delete(struct parse_events_term *term) 30518c2ecf20Sopenharmony_ci{ 30528c2ecf20Sopenharmony_ci if (term->array.nr_ranges) 30538c2ecf20Sopenharmony_ci zfree(&term->array.ranges); 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) 30568c2ecf20Sopenharmony_ci zfree(&term->val.str); 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci zfree(&term->config); 30598c2ecf20Sopenharmony_ci free(term); 30608c2ecf20Sopenharmony_ci} 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ciint parse_events_copy_term_list(struct list_head *old, 30638c2ecf20Sopenharmony_ci struct list_head **new) 30648c2ecf20Sopenharmony_ci{ 30658c2ecf20Sopenharmony_ci struct parse_events_term *term, *n; 30668c2ecf20Sopenharmony_ci int ret; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci if (!old) { 30698c2ecf20Sopenharmony_ci *new = NULL; 30708c2ecf20Sopenharmony_ci return 0; 30718c2ecf20Sopenharmony_ci } 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci *new = malloc(sizeof(struct list_head)); 30748c2ecf20Sopenharmony_ci if (!*new) 30758c2ecf20Sopenharmony_ci return -ENOMEM; 30768c2ecf20Sopenharmony_ci INIT_LIST_HEAD(*new); 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci list_for_each_entry (term, old, list) { 30798c2ecf20Sopenharmony_ci ret = parse_events_term__clone(&n, term); 30808c2ecf20Sopenharmony_ci if (ret) 30818c2ecf20Sopenharmony_ci return ret; 30828c2ecf20Sopenharmony_ci list_add_tail(&n->list, *new); 30838c2ecf20Sopenharmony_ci } 30848c2ecf20Sopenharmony_ci return 0; 30858c2ecf20Sopenharmony_ci} 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_civoid parse_events_terms__purge(struct list_head *terms) 30888c2ecf20Sopenharmony_ci{ 30898c2ecf20Sopenharmony_ci struct parse_events_term *term, *h; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci list_for_each_entry_safe(term, h, terms, list) { 30928c2ecf20Sopenharmony_ci list_del_init(&term->list); 30938c2ecf20Sopenharmony_ci parse_events_term__delete(term); 30948c2ecf20Sopenharmony_ci } 30958c2ecf20Sopenharmony_ci} 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_civoid parse_events_terms__delete(struct list_head *terms) 30988c2ecf20Sopenharmony_ci{ 30998c2ecf20Sopenharmony_ci if (!terms) 31008c2ecf20Sopenharmony_ci return; 31018c2ecf20Sopenharmony_ci parse_events_terms__purge(terms); 31028c2ecf20Sopenharmony_ci free(terms); 31038c2ecf20Sopenharmony_ci} 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_civoid parse_events__clear_array(struct parse_events_array *a) 31068c2ecf20Sopenharmony_ci{ 31078c2ecf20Sopenharmony_ci zfree(&a->ranges); 31088c2ecf20Sopenharmony_ci} 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_civoid parse_events_evlist_error(struct parse_events_state *parse_state, 31118c2ecf20Sopenharmony_ci int idx, const char *str) 31128c2ecf20Sopenharmony_ci{ 31138c2ecf20Sopenharmony_ci if (!parse_state->error) 31148c2ecf20Sopenharmony_ci return; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci parse_events__handle_error(parse_state->error, idx, strdup(str), NULL); 31178c2ecf20Sopenharmony_ci} 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_cistatic void config_terms_list(char *buf, size_t buf_sz) 31208c2ecf20Sopenharmony_ci{ 31218c2ecf20Sopenharmony_ci int i; 31228c2ecf20Sopenharmony_ci bool first = true; 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci buf[0] = '\0'; 31258c2ecf20Sopenharmony_ci for (i = 0; i < __PARSE_EVENTS__TERM_TYPE_NR; i++) { 31268c2ecf20Sopenharmony_ci const char *name = config_term_names[i]; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci if (!config_term_avail(i, NULL)) 31298c2ecf20Sopenharmony_ci continue; 31308c2ecf20Sopenharmony_ci if (!name) 31318c2ecf20Sopenharmony_ci continue; 31328c2ecf20Sopenharmony_ci if (name[0] == '<') 31338c2ecf20Sopenharmony_ci continue; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci if (strlen(buf) + strlen(name) + 2 >= buf_sz) 31368c2ecf20Sopenharmony_ci return; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci if (!first) 31398c2ecf20Sopenharmony_ci strcat(buf, ","); 31408c2ecf20Sopenharmony_ci else 31418c2ecf20Sopenharmony_ci first = false; 31428c2ecf20Sopenharmony_ci strcat(buf, name); 31438c2ecf20Sopenharmony_ci } 31448c2ecf20Sopenharmony_ci} 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci/* 31478c2ecf20Sopenharmony_ci * Return string contains valid config terms of an event. 31488c2ecf20Sopenharmony_ci * @additional_terms: For terms such as PMU sysfs terms. 31498c2ecf20Sopenharmony_ci */ 31508c2ecf20Sopenharmony_cichar *parse_events_formats_error_string(char *additional_terms) 31518c2ecf20Sopenharmony_ci{ 31528c2ecf20Sopenharmony_ci char *str; 31538c2ecf20Sopenharmony_ci /* "no-overwrite" is the longest name */ 31548c2ecf20Sopenharmony_ci char static_terms[__PARSE_EVENTS__TERM_TYPE_NR * 31558c2ecf20Sopenharmony_ci (sizeof("no-overwrite") - 1)]; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci config_terms_list(static_terms, sizeof(static_terms)); 31588c2ecf20Sopenharmony_ci /* valid terms */ 31598c2ecf20Sopenharmony_ci if (additional_terms) { 31608c2ecf20Sopenharmony_ci if (asprintf(&str, "valid terms: %s,%s", 31618c2ecf20Sopenharmony_ci additional_terms, static_terms) < 0) 31628c2ecf20Sopenharmony_ci goto fail; 31638c2ecf20Sopenharmony_ci } else { 31648c2ecf20Sopenharmony_ci if (asprintf(&str, "valid terms: %s", static_terms) < 0) 31658c2ecf20Sopenharmony_ci goto fail; 31668c2ecf20Sopenharmony_ci } 31678c2ecf20Sopenharmony_ci return str; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_cifail: 31708c2ecf20Sopenharmony_ci return NULL; 31718c2ecf20Sopenharmony_ci} 3172