1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2cd82a32eSJiri Olsa #include <linux/list.h> 3c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 432858480SArnaldo Carvalho de Melo #include <linux/string.h> 57f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 6c47a5599SJin Yao #include <linux/ctype.h> 7fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h> 8cd82a32eSJiri Olsa #include <sys/types.h> 9a43783aeSArnaldo Carvalho de Melo #include <errno.h> 10c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h> 117a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 12cd82a32eSJiri Olsa #include <unistd.h> 13cd82a32eSJiri Olsa #include <stdio.h> 14dc0a6202SAdrian Hunter #include <stdbool.h> 157d4bdab5SAdrian Hunter #include <stdarg.h> 16cd82a32eSJiri Olsa #include <dirent.h> 17cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 18410136f5SStephane Eranian #include <locale.h> 19fbc2844eSWilliam Cohen #include <regex.h> 209c3516d1SJiri Olsa #include <perf/cpumap.h> 21c47a5599SJin Yao #include <fnmatch.h> 225e51b0bbSArnaldo Carvalho de Melo #include "debug.h" 23e12ee9f7SAdrian Hunter #include "evsel.h" 24cd82a32eSJiri Olsa #include "pmu.h" 25cd82a32eSJiri Olsa #include "parse-events.h" 26933f82ffSSukadev Bhattiprolu #include "header.h" 27a067558eSArnaldo Carvalho de Melo #include "string2.h" 28fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h" 29d9664582SAndi Kleen #include "fncache.h" 3044462430SJin Yao #include "pmu-hybrid.h" 31cd82a32eSJiri Olsa 32e46fc8d9SArnaldo Carvalho de Melo struct perf_pmu perf_pmu__fake; 33e46fc8d9SArnaldo Carvalho de Melo 34ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 35ab1bf653SArnaldo Carvalho de Melo char *name; 36ab1bf653SArnaldo Carvalho de Melo int value; 37ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 38ab1bf653SArnaldo Carvalho de Melo struct list_head list; 39ab1bf653SArnaldo Carvalho de Melo }; 40ab1bf653SArnaldo Carvalho de Melo 41cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 42cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 43cd82a32eSJiri Olsa 44cd82a32eSJiri Olsa static LIST_HEAD(pmus); 45c5a26ea4SJin Yao static bool hybrid_scanned; 46cd82a32eSJiri Olsa 47cd82a32eSJiri Olsa /* 48cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 49cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 50cd82a32eSJiri Olsa */ 51cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 52cd82a32eSJiri Olsa { 53cd82a32eSJiri Olsa struct dirent *evt_ent; 54cd82a32eSJiri Olsa DIR *format_dir; 55cd82a32eSJiri Olsa int ret = 0; 56cd82a32eSJiri Olsa 57cd82a32eSJiri Olsa format_dir = opendir(dir); 58cd82a32eSJiri Olsa if (!format_dir) 59cd82a32eSJiri Olsa return -EINVAL; 60cd82a32eSJiri Olsa 61cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 62cd82a32eSJiri Olsa char path[PATH_MAX]; 63cd82a32eSJiri Olsa char *name = evt_ent->d_name; 64cd82a32eSJiri Olsa FILE *file; 65cd82a32eSJiri Olsa 66cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 67cd82a32eSJiri Olsa continue; 68cd82a32eSJiri Olsa 69cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa ret = -EINVAL; 72cd82a32eSJiri Olsa file = fopen(path, "r"); 73cd82a32eSJiri Olsa if (!file) 74cd82a32eSJiri Olsa break; 75cd82a32eSJiri Olsa 76cd82a32eSJiri Olsa perf_pmu_in = file; 77cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 78cd82a32eSJiri Olsa fclose(file); 79cd82a32eSJiri Olsa } 80cd82a32eSJiri Olsa 81cd82a32eSJiri Olsa closedir(format_dir); 82cd82a32eSJiri Olsa return ret; 83cd82a32eSJiri Olsa } 84cd82a32eSJiri Olsa 85cd82a32eSJiri Olsa /* 86cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 87cd82a32eSJiri Olsa * located at: 88cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 89cd82a32eSJiri Olsa */ 90b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 91cd82a32eSJiri Olsa { 92cd82a32eSJiri Olsa char path[PATH_MAX]; 93cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 94cd82a32eSJiri Olsa 95cd82a32eSJiri Olsa if (!sysfs) 96cd82a32eSJiri Olsa return -1; 97cd82a32eSJiri Olsa 98cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9950a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 100cd82a32eSJiri Olsa 101d9664582SAndi Kleen if (!file_available(path)) 102d9664582SAndi Kleen return 0; 103cd82a32eSJiri Olsa 104cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 105cd82a32eSJiri Olsa return -1; 106cd82a32eSJiri Olsa 107cd82a32eSJiri Olsa return 0; 108cd82a32eSJiri Olsa } 109cd82a32eSJiri Olsa 110a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 111d02fc6bcSAndi Kleen { 112d02fc6bcSAndi Kleen char *lc; 113d02fc6bcSAndi Kleen int ret = 0; 114d02fc6bcSAndi Kleen 115d02fc6bcSAndi Kleen /* 116d02fc6bcSAndi Kleen * save current locale 117d02fc6bcSAndi Kleen */ 118d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 119d02fc6bcSAndi Kleen 120d02fc6bcSAndi Kleen /* 121d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 122d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 123d02fc6bcSAndi Kleen * call below. 124d02fc6bcSAndi Kleen */ 125d02fc6bcSAndi Kleen lc = strdup(lc); 126d02fc6bcSAndi Kleen if (!lc) { 127d02fc6bcSAndi Kleen ret = -ENOMEM; 128d02fc6bcSAndi Kleen goto out; 129d02fc6bcSAndi Kleen } 130d02fc6bcSAndi Kleen 131d02fc6bcSAndi Kleen /* 132d02fc6bcSAndi Kleen * force to C locale to ensure kernel 133d02fc6bcSAndi Kleen * scale string is converted correctly. 134d02fc6bcSAndi Kleen * kernel uses default C locale. 135d02fc6bcSAndi Kleen */ 136d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 137d02fc6bcSAndi Kleen 138d02fc6bcSAndi Kleen *sval = strtod(scale, end); 139d02fc6bcSAndi Kleen 140d02fc6bcSAndi Kleen out: 141d02fc6bcSAndi Kleen /* restore locale */ 142d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 143d02fc6bcSAndi Kleen free(lc); 144d02fc6bcSAndi Kleen return ret; 145d02fc6bcSAndi Kleen } 146d02fc6bcSAndi Kleen 147410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 148410136f5SStephane Eranian { 149410136f5SStephane Eranian struct stat st; 150410136f5SStephane Eranian ssize_t sret; 151410136f5SStephane Eranian char scale[128]; 152410136f5SStephane Eranian int fd, ret = -1; 153410136f5SStephane Eranian char path[PATH_MAX]; 154410136f5SStephane Eranian 15511a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 156410136f5SStephane Eranian 157410136f5SStephane Eranian fd = open(path, O_RDONLY); 158410136f5SStephane Eranian if (fd == -1) 159410136f5SStephane Eranian return -1; 160410136f5SStephane Eranian 161410136f5SStephane Eranian if (fstat(fd, &st) < 0) 162410136f5SStephane Eranian goto error; 163410136f5SStephane Eranian 164410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 165410136f5SStephane Eranian if (sret < 0) 166410136f5SStephane Eranian goto error; 167410136f5SStephane Eranian 1689ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1699ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1709ecae065SMadhavan Srinivasan else 171410136f5SStephane Eranian scale[sret] = '\0'; 1729ecae065SMadhavan Srinivasan 173a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 174410136f5SStephane Eranian error: 175410136f5SStephane Eranian close(fd); 176410136f5SStephane Eranian return ret; 177410136f5SStephane Eranian } 178410136f5SStephane Eranian 179410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 180410136f5SStephane Eranian { 181410136f5SStephane Eranian char path[PATH_MAX]; 182410136f5SStephane Eranian ssize_t sret; 183410136f5SStephane Eranian int fd; 184410136f5SStephane Eranian 18511a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 186410136f5SStephane Eranian 187410136f5SStephane Eranian fd = open(path, O_RDONLY); 188410136f5SStephane Eranian if (fd == -1) 189410136f5SStephane Eranian return -1; 190410136f5SStephane Eranian 191410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 192410136f5SStephane Eranian if (sret < 0) 193410136f5SStephane Eranian goto error; 194410136f5SStephane Eranian 195410136f5SStephane Eranian close(fd); 196410136f5SStephane Eranian 1979ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1989ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1999ecae065SMadhavan Srinivasan else 200410136f5SStephane Eranian alias->unit[sret] = '\0'; 201410136f5SStephane Eranian 202410136f5SStephane Eranian return 0; 203410136f5SStephane Eranian error: 204410136f5SStephane Eranian close(fd); 205410136f5SStephane Eranian alias->unit[0] = '\0'; 206410136f5SStephane Eranian return -1; 207410136f5SStephane Eranian } 208410136f5SStephane Eranian 209044330c1SMatt Fleming static int 210044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 211044330c1SMatt Fleming { 212044330c1SMatt Fleming char path[PATH_MAX]; 213044330c1SMatt Fleming int fd; 214044330c1SMatt Fleming 21511a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 216044330c1SMatt Fleming 217044330c1SMatt Fleming fd = open(path, O_RDONLY); 218044330c1SMatt Fleming if (fd == -1) 219044330c1SMatt Fleming return -1; 220044330c1SMatt Fleming 221044330c1SMatt Fleming close(fd); 222044330c1SMatt Fleming 223044330c1SMatt Fleming alias->per_pkg = true; 224044330c1SMatt Fleming return 0; 225044330c1SMatt Fleming } 226044330c1SMatt Fleming 2271d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2281d9e446bSJiri Olsa char *dir, char *name) 2291d9e446bSJiri Olsa { 2301d9e446bSJiri Olsa char path[PATH_MAX]; 2311d9e446bSJiri Olsa int fd; 2321d9e446bSJiri Olsa 23311a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2341d9e446bSJiri Olsa 2351d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2361d9e446bSJiri Olsa if (fd == -1) 2371d9e446bSJiri Olsa return -1; 2381d9e446bSJiri Olsa 2391d9e446bSJiri Olsa alias->snapshot = true; 2401d9e446bSJiri Olsa close(fd); 2411d9e446bSJiri Olsa return 0; 2421d9e446bSJiri Olsa } 2431d9e446bSJiri Olsa 2446dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2456dde6429SThomas Richter char **new_str) 2466dde6429SThomas Richter { 2476dde6429SThomas Richter if (!*old_str) 2486dde6429SThomas Richter goto set_new; 2496dde6429SThomas Richter 2506dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2516dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2526dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2536dde6429SThomas Richter name, field); 2546dde6429SThomas Richter zfree(old_str); 2556dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2566dde6429SThomas Richter return; 2576dde6429SThomas Richter set_new: 2586dde6429SThomas Richter *old_str = *new_str; 2596dde6429SThomas Richter *new_str = NULL; 2606dde6429SThomas Richter } 2616dde6429SThomas Richter 2626dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2636dde6429SThomas Richter struct perf_pmu_alias *newalias) 2646dde6429SThomas Richter { 2656dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2666dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2676dde6429SThomas Richter &newalias->long_desc); 2686dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2696dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, 2706dde6429SThomas Richter &newalias->metric_expr); 2716dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, 2726dde6429SThomas Richter &newalias->metric_name); 2736dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2746dde6429SThomas Richter old->scale = newalias->scale; 2756dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2766dde6429SThomas Richter old->snapshot = newalias->snapshot; 2776dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2786dde6429SThomas Richter } 2796dde6429SThomas Richter 2806dde6429SThomas Richter /* Delete an alias entry. */ 28122fe5a25SNamhyung Kim void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2826dde6429SThomas Richter { 2836dde6429SThomas Richter zfree(&newalias->name); 2846dde6429SThomas Richter zfree(&newalias->desc); 2856dde6429SThomas Richter zfree(&newalias->long_desc); 2866dde6429SThomas Richter zfree(&newalias->topic); 2876dde6429SThomas Richter zfree(&newalias->str); 2886dde6429SThomas Richter zfree(&newalias->metric_expr); 2896dde6429SThomas Richter zfree(&newalias->metric_name); 29032705de7SJin Yao zfree(&newalias->pmu_name); 2916dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 2926dde6429SThomas Richter free(newalias); 2936dde6429SThomas Richter } 2946dde6429SThomas Richter 2956dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 2966dde6429SThomas Richter * present merge both of them to combine all information. 2976dde6429SThomas Richter */ 2986dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 2996dde6429SThomas Richter struct list_head *alist) 3006dde6429SThomas Richter { 3016dde6429SThomas Richter struct perf_pmu_alias *a; 3026dde6429SThomas Richter 3036dde6429SThomas Richter list_for_each_entry(a, alist, list) { 3046dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 30532705de7SJin Yao if (newalias->pmu_name && a->pmu_name && 30632705de7SJin Yao !strcasecmp(newalias->pmu_name, a->pmu_name)) { 30732705de7SJin Yao continue; 30832705de7SJin Yao } 3096dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 3106dde6429SThomas Richter perf_pmu_free_alias(newalias); 3116dde6429SThomas Richter return true; 3126dde6429SThomas Richter } 3136dde6429SThomas Richter } 3146dde6429SThomas Richter return false; 3156dde6429SThomas Richter } 3166dde6429SThomas Richter 31770c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 31847f572aaSIan Rogers char *desc, char *val, const struct pmu_event *pe) 319a6146d50SZheng Yan { 3200c24d6fbSThomas Richter struct parse_events_term *term; 3215c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 322a6146d50SZheng Yan int ret; 323fedb2b51SAndi Kleen int num; 3240c24d6fbSThomas Richter char newval[256]; 325eab35953SJin Yao char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL, 32632705de7SJin Yao *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL, 32732705de7SJin Yao *pmu_name = NULL; 328eab35953SJin Yao 329eab35953SJin Yao if (pe) { 330eab35953SJin Yao long_desc = (char *)pe->long_desc; 331eab35953SJin Yao topic = (char *)pe->topic; 332eab35953SJin Yao unit = (char *)pe->unit; 333eab35953SJin Yao perpkg = (char *)pe->perpkg; 334eab35953SJin Yao metric_expr = (char *)pe->metric_expr; 335eab35953SJin Yao metric_name = (char *)pe->metric_name; 336eab35953SJin Yao deprecated = (char *)pe->deprecated; 33732705de7SJin Yao pmu_name = (char *)pe->pmu; 338eab35953SJin Yao } 339a6146d50SZheng Yan 340a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 341a6146d50SZheng Yan if (!alias) 342a6146d50SZheng Yan return -ENOMEM; 343a6146d50SZheng Yan 344a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 345410136f5SStephane Eranian alias->scale = 1.0; 346410136f5SStephane Eranian alias->unit[0] = '\0'; 347044330c1SMatt Fleming alias->per_pkg = false; 34884530920SStephane Eranian alias->snapshot = false; 349a7f6c8c8SJin Yao alias->deprecated = false; 350410136f5SStephane Eranian 35170c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 352a6146d50SZheng Yan if (ret) { 35370c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 354a6146d50SZheng Yan free(alias); 355a6146d50SZheng Yan return ret; 356a6146d50SZheng Yan } 357a6146d50SZheng Yan 3580c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3590c24d6fbSThomas Richter * platforms have terms specified as 3600c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3610c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3620c24d6fbSThomas Richter * 3630c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3640c24d6fbSThomas Richter */ 3650c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3660c24d6fbSThomas Richter ret = 0; 3670c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3680c24d6fbSThomas Richter if (ret) 3690c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3700c24d6fbSThomas Richter ","); 3710c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3720c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3730c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3740c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3750c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3760c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3770c24d6fbSThomas Richter } 3780c24d6fbSThomas Richter 379a6146d50SZheng Yan alias->name = strdup(name); 38070c646e0SSukadev Bhattiprolu if (dir) { 381410136f5SStephane Eranian /* 382410136f5SStephane Eranian * load unit name and scale if available 383410136f5SStephane Eranian */ 384410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 385410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 386044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 3871d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 38870c646e0SSukadev Bhattiprolu } 389410136f5SStephane Eranian 39000636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 39196284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 39208e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 393c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 394c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 395dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 396fedb2b51SAndi Kleen if (unit) { 397a55ab7c4SJin Yao if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) 398fedb2b51SAndi Kleen return -1; 399fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 400fedb2b51SAndi Kleen } 401fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 4020c24d6fbSThomas Richter alias->str = strdup(newval); 40332705de7SJin Yao alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; 404f2361024SAndi Kleen 405a7f6c8c8SJin Yao if (deprecated) 406a7f6c8c8SJin Yao alias->deprecated = true; 407a7f6c8c8SJin Yao 4086dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 409a6146d50SZheng Yan list_add_tail(&alias->list, list); 410410136f5SStephane Eranian 411a6146d50SZheng Yan return 0; 412a6146d50SZheng Yan } 413a6146d50SZheng Yan 41470c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 41570c646e0SSukadev Bhattiprolu { 41670c646e0SSukadev Bhattiprolu char buf[256]; 41770c646e0SSukadev Bhattiprolu int ret; 41870c646e0SSukadev Bhattiprolu 41970c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 42070c646e0SSukadev Bhattiprolu if (ret == 0) 42170c646e0SSukadev Bhattiprolu return -EINVAL; 42270c646e0SSukadev Bhattiprolu 42370c646e0SSukadev Bhattiprolu buf[ret] = 0; 42470c646e0SSukadev Bhattiprolu 425ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 42613c230abSArnaldo Carvalho de Melo strim(buf); 427ea23ac73SThomas Richter 428eab35953SJin Yao return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL); 42970c646e0SSukadev Bhattiprolu } 43070c646e0SSukadev Bhattiprolu 43146441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 43246441bdcSMatt Fleming { 43346441bdcSMatt Fleming size_t len; 43446441bdcSMatt Fleming 43546441bdcSMatt Fleming len = strlen(name); 43646441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 43746441bdcSMatt Fleming return true; 43846441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 43946441bdcSMatt Fleming return true; 440044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 441044330c1SMatt Fleming return true; 4421d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4431d9e446bSJiri Olsa return true; 44446441bdcSMatt Fleming 44546441bdcSMatt Fleming return false; 44646441bdcSMatt Fleming } 44746441bdcSMatt Fleming 448a6146d50SZheng Yan /* 449a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 450a6146d50SZheng Yan * specified in 'dir' parameter. 451a6146d50SZheng Yan */ 452a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 453a6146d50SZheng Yan { 454a6146d50SZheng Yan struct dirent *evt_ent; 455a6146d50SZheng Yan DIR *event_dir; 456a6146d50SZheng Yan 457a6146d50SZheng Yan event_dir = opendir(dir); 458a6146d50SZheng Yan if (!event_dir) 459a6146d50SZheng Yan return -EINVAL; 460a6146d50SZheng Yan 461940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 462a6146d50SZheng Yan char path[PATH_MAX]; 463a6146d50SZheng Yan char *name = evt_ent->d_name; 464a6146d50SZheng Yan FILE *file; 465a6146d50SZheng Yan 466a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 467a6146d50SZheng Yan continue; 468a6146d50SZheng Yan 469410136f5SStephane Eranian /* 47046441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 471410136f5SStephane Eranian */ 47246441bdcSMatt Fleming if (pmu_alias_info_file(name)) 473410136f5SStephane Eranian continue; 474410136f5SStephane Eranian 47577f18153SJiri Olsa scnprintf(path, PATH_MAX, "%s/%s", dir, name); 476a6146d50SZheng Yan 477a6146d50SZheng Yan file = fopen(path, "r"); 478940db6dcSAndi Kleen if (!file) { 479940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 480940db6dcSAndi Kleen continue; 481940db6dcSAndi Kleen } 482410136f5SStephane Eranian 483940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 484940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 485a6146d50SZheng Yan fclose(file); 486a6146d50SZheng Yan } 487a6146d50SZheng Yan 488a6146d50SZheng Yan closedir(event_dir); 489940db6dcSAndi Kleen return 0; 490a6146d50SZheng Yan } 491a6146d50SZheng Yan 492a6146d50SZheng Yan /* 493a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 494a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 495a6146d50SZheng Yan */ 496b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 497a6146d50SZheng Yan { 498a6146d50SZheng Yan char path[PATH_MAX]; 499cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 500a6146d50SZheng Yan 501a6146d50SZheng Yan if (!sysfs) 502a6146d50SZheng Yan return -1; 503a6146d50SZheng Yan 504a6146d50SZheng Yan snprintf(path, PATH_MAX, 505a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 506a6146d50SZheng Yan 507d9664582SAndi Kleen if (!file_available(path)) 508d9664582SAndi Kleen return 0; 509a6146d50SZheng Yan 510a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 511a6146d50SZheng Yan return -1; 512a6146d50SZheng Yan 513a6146d50SZheng Yan return 0; 514a6146d50SZheng Yan } 515a6146d50SZheng Yan 5165c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 517a6146d50SZheng Yan struct list_head *terms) 518a6146d50SZheng Yan { 5197c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 520a6146d50SZheng Yan LIST_HEAD(list); 521a6146d50SZheng Yan int ret; 522a6146d50SZheng Yan 523a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5247c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 525a6146d50SZheng Yan if (ret) { 526682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 527a6146d50SZheng Yan return ret; 528a6146d50SZheng Yan } 529c2f1ceadSAndi Kleen /* 530c2f1ceadSAndi Kleen * Weak terms don't override command line options, 531c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 532c2f1ceadSAndi Kleen */ 533c2f1ceadSAndi Kleen cloned->weak = true; 5347c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 535a6146d50SZheng Yan } 536a6146d50SZheng Yan list_splice(&list, terms); 537a6146d50SZheng Yan return 0; 538a6146d50SZheng Yan } 539a6146d50SZheng Yan 540cd82a32eSJiri Olsa /* 541cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 542cd82a32eSJiri Olsa * located at: 543cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 544cd82a32eSJiri Olsa */ 545b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 546cd82a32eSJiri Olsa { 547cd82a32eSJiri Olsa char path[PATH_MAX]; 548cd82a32eSJiri Olsa FILE *file; 549cd82a32eSJiri Olsa int ret = 0; 550cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 551cd82a32eSJiri Olsa 552cd82a32eSJiri Olsa if (!sysfs) 553cd82a32eSJiri Olsa return -1; 554cd82a32eSJiri Olsa 555cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 55650a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 557cd82a32eSJiri Olsa 558d9664582SAndi Kleen if (access(path, R_OK) < 0) 559cd82a32eSJiri Olsa return -1; 560cd82a32eSJiri Olsa 561cd82a32eSJiri Olsa file = fopen(path, "r"); 562cd82a32eSJiri Olsa if (!file) 563cd82a32eSJiri Olsa return -EINVAL; 564cd82a32eSJiri Olsa 565cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 566cd82a32eSJiri Olsa ret = -1; 567cd82a32eSJiri Olsa 568cd82a32eSJiri Olsa fclose(file); 569cd82a32eSJiri Olsa return ret; 570cd82a32eSJiri Olsa } 571cd82a32eSJiri Olsa 57250a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 57350a9667cSRobert Richter static void pmu_read_sysfs(void) 57450a9667cSRobert Richter { 57550a9667cSRobert Richter char path[PATH_MAX]; 57650a9667cSRobert Richter DIR *dir; 57750a9667cSRobert Richter struct dirent *dent; 578cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 57950a9667cSRobert Richter 58050a9667cSRobert Richter if (!sysfs) 58150a9667cSRobert Richter return; 58250a9667cSRobert Richter 58350a9667cSRobert Richter snprintf(path, PATH_MAX, 58450a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 58550a9667cSRobert Richter 58650a9667cSRobert Richter dir = opendir(path); 58750a9667cSRobert Richter if (!dir) 58850a9667cSRobert Richter return; 58950a9667cSRobert Richter 59050a9667cSRobert Richter while ((dent = readdir(dir))) { 59150a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 59250a9667cSRobert Richter continue; 59350a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 59450a9667cSRobert Richter perf_pmu__find(dent->d_name); 59550a9667cSRobert Richter } 59650a9667cSRobert Richter 59750a9667cSRobert Richter closedir(dir); 59850a9667cSRobert Richter } 59950a9667cSRobert Richter 600f854839bSJiri Olsa static struct perf_cpu_map *__pmu_cpumask(const char *path) 60166ec1191SMark Rutland { 60266ec1191SMark Rutland FILE *file; 603f854839bSJiri Olsa struct perf_cpu_map *cpus; 60466ec1191SMark Rutland 60566ec1191SMark Rutland file = fopen(path, "r"); 60666ec1191SMark Rutland if (!file) 60766ec1191SMark Rutland return NULL; 60866ec1191SMark Rutland 6099c3516d1SJiri Olsa cpus = perf_cpu_map__read(file); 61066ec1191SMark Rutland fclose(file); 61166ec1191SMark Rutland return cpus; 61266ec1191SMark Rutland } 61366ec1191SMark Rutland 61466ec1191SMark Rutland /* 61566ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 61666ec1191SMark Rutland * may have a "cpus" file. 61766ec1191SMark Rutland */ 61851d54847SJohn Garry #define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier" 61966ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 62066ec1191SMark Rutland 621f854839bSJiri Olsa static struct perf_cpu_map *pmu_cpumask(const char *name) 6227ae92e74SYan, Zheng { 6237ae92e74SYan, Zheng char path[PATH_MAX]; 624f854839bSJiri Olsa struct perf_cpu_map *cpus; 625cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 6267e3fcffeSMark Rutland const char *templates[] = { 62766ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 62866ec1191SMark Rutland CPUS_TEMPLATE_CPU, 6297e3fcffeSMark Rutland NULL 6307e3fcffeSMark Rutland }; 6317e3fcffeSMark Rutland const char **template; 6327ae92e74SYan, Zheng 6337ae92e74SYan, Zheng if (!sysfs) 6347ae92e74SYan, Zheng return NULL; 6357ae92e74SYan, Zheng 6367e3fcffeSMark Rutland for (template = templates; *template; template++) { 6377e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 63866ec1191SMark Rutland cpus = __pmu_cpumask(path); 63966ec1191SMark Rutland if (cpus) 64066ec1191SMark Rutland return cpus; 6417e3fcffeSMark Rutland } 6427ae92e74SYan, Zheng 6437ae92e74SYan, Zheng return NULL; 64466ec1191SMark Rutland } 6457ae92e74SYan, Zheng 64666ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 64766ec1191SMark Rutland { 64866ec1191SMark Rutland char path[PATH_MAX]; 649d9664582SAndi Kleen const char *sysfs; 6507ae92e74SYan, Zheng 65144462430SJin Yao if (perf_pmu__hybrid_mounted(name)) 65244462430SJin Yao return false; 65344462430SJin Yao 654d9664582SAndi Kleen sysfs = sysfs__mountpoint(); 65566ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 656d9664582SAndi Kleen return file_available(path); 6577ae92e74SYan, Zheng } 6587ae92e74SYan, Zheng 65951d54847SJohn Garry static char *pmu_id(const char *name) 66051d54847SJohn Garry { 66151d54847SJohn Garry char path[PATH_MAX], *str; 66251d54847SJohn Garry size_t len; 66351d54847SJohn Garry 66451d54847SJohn Garry snprintf(path, PATH_MAX, SYS_TEMPLATE_ID, name); 66551d54847SJohn Garry 66651d54847SJohn Garry if (sysfs__read_str(path, &str, &len) < 0) 66751d54847SJohn Garry return NULL; 66851d54847SJohn Garry 66951d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 67051d54847SJohn Garry 67151d54847SJohn Garry return str; 67251d54847SJohn Garry } 67351d54847SJohn Garry 674933f82ffSSukadev Bhattiprolu /* 67514b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 676292c34c1SKan Liang * platforms. 677292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 67814b22ae0SGanapatrao Kulkarni */ 679292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 68014b22ae0SGanapatrao Kulkarni { 68114b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 68214b22ae0SGanapatrao Kulkarni const char *sysfs = sysfs__mountpoint(); 68314b22ae0SGanapatrao Kulkarni 68414b22ae0SGanapatrao Kulkarni if (!sysfs) 68514b22ae0SGanapatrao Kulkarni return 0; 68614b22ae0SGanapatrao Kulkarni 68714b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (specific to arm) */ 68814b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", 68914b22ae0SGanapatrao Kulkarni sysfs, name); 690d9664582SAndi Kleen return file_available(path); 69114b22ae0SGanapatrao Kulkarni } 69214b22ae0SGanapatrao Kulkarni 69329be2fe0SIan Rogers char *perf_pmu__getcpuid(struct perf_pmu *pmu) 694d77ade9fSAndi Kleen { 695d77ade9fSAndi Kleen char *cpuid; 696d77ade9fSAndi Kleen static bool printed; 697d77ade9fSAndi Kleen 698d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 699d77ade9fSAndi Kleen if (cpuid) 700d77ade9fSAndi Kleen cpuid = strdup(cpuid); 701d77ade9fSAndi Kleen if (!cpuid) 70254e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 703d77ade9fSAndi Kleen if (!cpuid) 704d77ade9fSAndi Kleen return NULL; 705d77ade9fSAndi Kleen 706d77ade9fSAndi Kleen if (!printed) { 707d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 708d77ade9fSAndi Kleen printed = true; 709d77ade9fSAndi Kleen } 710d77ade9fSAndi Kleen return cpuid; 711d77ade9fSAndi Kleen } 712d77ade9fSAndi Kleen 713eeac7730SIan Rogers __weak const struct pmu_event *pmu_events_table__find(void) 714e126bef5SJohn Garry { 715eeac7730SIan Rogers return perf_pmu__find_table(NULL); 716e126bef5SJohn Garry } 717e126bef5SJohn Garry 718c07d5c92SJohn Garry /* 719c07d5c92SJohn Garry * Suffix must be in form tok_{digits}, or tok{digits}, or same as pmu_name 720c07d5c92SJohn Garry * to be valid. 721c07d5c92SJohn Garry */ 722c07d5c92SJohn Garry static bool perf_pmu__valid_suffix(const char *pmu_name, char *tok) 723c47a5599SJin Yao { 724c07d5c92SJohn Garry const char *p; 725c47a5599SJin Yao 726c47a5599SJin Yao if (strncmp(pmu_name, tok, strlen(tok))) 727c47a5599SJin Yao return false; 728c47a5599SJin Yao 729c47a5599SJin Yao p = pmu_name + strlen(tok); 730c47a5599SJin Yao if (*p == 0) 731c47a5599SJin Yao return true; 732c47a5599SJin Yao 733c07d5c92SJohn Garry if (*p == '_') 734c47a5599SJin Yao ++p; 735c07d5c92SJohn Garry 736c07d5c92SJohn Garry /* Ensure we end in a number */ 737c07d5c92SJohn Garry while (1) { 738c07d5c92SJohn Garry if (!isdigit(*p)) 739c47a5599SJin Yao return false; 740c07d5c92SJohn Garry if (*(++p) == 0) 741c07d5c92SJohn Garry break; 742c07d5c92SJohn Garry } 743c47a5599SJin Yao 744c47a5599SJin Yao return true; 745c47a5599SJin Yao } 746c47a5599SJin Yao 7475b9a5000SJohn Garry bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 748730670b1SJohn Garry { 749730670b1SJohn Garry char *tmp = NULL, *tok, *str; 750730670b1SJohn Garry bool res; 751730670b1SJohn Garry 752730670b1SJohn Garry str = strdup(pmu_name); 753730670b1SJohn Garry if (!str) 754730670b1SJohn Garry return false; 755730670b1SJohn Garry 756730670b1SJohn Garry /* 757730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 758730670b1SJohn Garry */ 759730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 760730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 761730670b1SJohn Garry res = false; 762730670b1SJohn Garry goto out; 763730670b1SJohn Garry } 764730670b1SJohn Garry 765730670b1SJohn Garry /* 766730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 767730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 768730670b1SJohn Garry * 769730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 770730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 771730670b1SJohn Garry * "pmunameY". 772730670b1SJohn Garry */ 773c07d5c92SJohn Garry while (1) { 774c07d5c92SJohn Garry char *next_tok = strtok_r(NULL, ",", &tmp); 775c07d5c92SJohn Garry 776730670b1SJohn Garry name = strstr(name, tok); 777c07d5c92SJohn Garry if (!name || 778c07d5c92SJohn Garry (!next_tok && !perf_pmu__valid_suffix(name, tok))) { 779730670b1SJohn Garry res = false; 780730670b1SJohn Garry goto out; 781730670b1SJohn Garry } 782c07d5c92SJohn Garry if (!next_tok) 783c07d5c92SJohn Garry break; 784c07d5c92SJohn Garry tok = next_tok; 785c07d5c92SJohn Garry name += strlen(tok); 786730670b1SJohn Garry } 787730670b1SJohn Garry 788730670b1SJohn Garry res = true; 789730670b1SJohn Garry out: 790730670b1SJohn Garry free(str); 791730670b1SJohn Garry return res; 792730670b1SJohn Garry } 793730670b1SJohn Garry 794*660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data { 795*660842e4SIan Rogers struct list_head *head; 796*660842e4SIan Rogers const char *name; 797*660842e4SIan Rogers const char *cpu_name; 798*660842e4SIan Rogers struct perf_pmu *pmu; 799*660842e4SIan Rogers }; 800*660842e4SIan Rogers 801*660842e4SIan Rogers static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, 802*660842e4SIan Rogers const struct pmu_event *table __maybe_unused, 803*660842e4SIan Rogers void *vdata) 804*660842e4SIan Rogers { 805*660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data *data = vdata; 806*660842e4SIan Rogers const char *pname = pe->pmu ? pe->pmu : data->cpu_name; 807*660842e4SIan Rogers 808*660842e4SIan Rogers if (!pe->name) 809*660842e4SIan Rogers return 0; 810*660842e4SIan Rogers 811*660842e4SIan Rogers if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name)) 812*660842e4SIan Rogers goto new_alias; 813*660842e4SIan Rogers 814*660842e4SIan Rogers if (strcmp(pname, data->name)) 815*660842e4SIan Rogers return 0; 816*660842e4SIan Rogers 817*660842e4SIan Rogers new_alias: 818*660842e4SIan Rogers /* need type casts to override 'const' */ 819*660842e4SIan Rogers __perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc, 820*660842e4SIan Rogers (char *)pe->event, pe); 821*660842e4SIan Rogers return 0; 822*660842e4SIan Rogers } 823*660842e4SIan Rogers 824933f82ffSSukadev Bhattiprolu /* 825933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 826933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 827933f82ffSSukadev Bhattiprolu * as aliases. 828933f82ffSSukadev Bhattiprolu */ 829eeac7730SIan Rogers void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu, 830eeac7730SIan Rogers const struct pmu_event *table) 831933f82ffSSukadev Bhattiprolu { 832*660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data data = { 833*660842e4SIan Rogers .head = head, 834*660842e4SIan Rogers .name = pmu->name, 835*660842e4SIan Rogers .cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu", 836*660842e4SIan Rogers .pmu = pmu, 837*660842e4SIan Rogers }; 838fedb2b51SAndi Kleen 839*660842e4SIan Rogers pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data); 840933f82ffSSukadev Bhattiprolu } 841933f82ffSSukadev Bhattiprolu 842e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 843e45ad701SJohn Garry { 844eeac7730SIan Rogers const struct pmu_event *table; 845e45ad701SJohn Garry 846eeac7730SIan Rogers table = perf_pmu__find_table(pmu); 847eeac7730SIan Rogers if (!table) 848e45ad701SJohn Garry return; 849e45ad701SJohn Garry 850eeac7730SIan Rogers pmu_add_cpu_aliases_table(head, pmu, table); 851e45ad701SJohn Garry } 852e45ad701SJohn Garry 8534513c719SJohn Garry struct pmu_sys_event_iter_data { 8544513c719SJohn Garry struct list_head *head; 8554513c719SJohn Garry struct perf_pmu *pmu; 8564513c719SJohn Garry }; 8574513c719SJohn Garry 85829be2fe0SIan Rogers static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, 85929be2fe0SIan Rogers const struct pmu_event *table __maybe_unused, 86029be2fe0SIan Rogers void *data) 8614513c719SJohn Garry { 8624513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8634513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8644513c719SJohn Garry 8654513c719SJohn Garry if (!pe->name) { 8664513c719SJohn Garry if (pe->metric_group || pe->metric_name) 8674513c719SJohn Garry return 0; 8684513c719SJohn Garry return -EINVAL; 8694513c719SJohn Garry } 8704513c719SJohn Garry 8714513c719SJohn Garry if (!pe->compat || !pe->pmu) 8724513c719SJohn Garry return 0; 8734513c719SJohn Garry 8744513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8754513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 8764513c719SJohn Garry __perf_pmu__new_alias(idata->head, NULL, 8774513c719SJohn Garry (char *)pe->name, 8784513c719SJohn Garry (char *)pe->desc, 8794513c719SJohn Garry (char *)pe->event, 880eab35953SJin Yao pe); 8814513c719SJohn Garry } 8824513c719SJohn Garry 8834513c719SJohn Garry return 0; 8844513c719SJohn Garry } 8854513c719SJohn Garry 886e199f47fSJohn Garry void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 8874513c719SJohn Garry { 8884513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 8894513c719SJohn Garry .head = head, 8904513c719SJohn Garry .pmu = pmu, 8914513c719SJohn Garry }; 8924513c719SJohn Garry 8934513c719SJohn Garry if (!pmu->id) 8944513c719SJohn Garry return; 8954513c719SJohn Garry 8964513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 8974513c719SJohn Garry } 8984513c719SJohn Garry 899c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 900dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 901dc0a6202SAdrian Hunter { 902dc0a6202SAdrian Hunter return NULL; 903dc0a6202SAdrian Hunter } 904dc0a6202SAdrian Hunter 90513d60ba0SKan Liang char * __weak 90613d60ba0SKan Liang pmu_find_real_name(const char *name) 90713d60ba0SKan Liang { 90813d60ba0SKan Liang return (char *)name; 90913d60ba0SKan Liang } 91013d60ba0SKan Liang 91113d60ba0SKan Liang char * __weak 91213d60ba0SKan Liang pmu_find_alias_name(const char *name __maybe_unused) 91313d60ba0SKan Liang { 91413d60ba0SKan Liang return NULL; 91513d60ba0SKan Liang } 91613d60ba0SKan Liang 91790a86bdeSJiri Olsa static int pmu_max_precise(const char *name) 91890a86bdeSJiri Olsa { 91990a86bdeSJiri Olsa char path[PATH_MAX]; 92090a86bdeSJiri Olsa int max_precise = -1; 92190a86bdeSJiri Olsa 92290a86bdeSJiri Olsa scnprintf(path, PATH_MAX, 92390a86bdeSJiri Olsa "bus/event_source/devices/%s/caps/max_precise", 92490a86bdeSJiri Olsa name); 92590a86bdeSJiri Olsa 92690a86bdeSJiri Olsa sysfs__read_int(path, &max_precise); 92790a86bdeSJiri Olsa return max_precise; 92890a86bdeSJiri Olsa } 92990a86bdeSJiri Olsa 93013d60ba0SKan Liang static struct perf_pmu *pmu_lookup(const char *lookup_name) 931cd82a32eSJiri Olsa { 932cd82a32eSJiri Olsa struct perf_pmu *pmu; 933cd82a32eSJiri Olsa LIST_HEAD(format); 934a6146d50SZheng Yan LIST_HEAD(aliases); 935cd82a32eSJiri Olsa __u32 type; 93613d60ba0SKan Liang char *name = pmu_find_real_name(lookup_name); 93749afa7f6SJin Yao bool is_hybrid = perf_pmu__hybrid_mounted(name); 93813d60ba0SKan Liang char *alias_name; 93949afa7f6SJin Yao 94049afa7f6SJin Yao /* 94149afa7f6SJin Yao * Check pmu name for hybrid and the pmu may be invalid in sysfs 94249afa7f6SJin Yao */ 94349afa7f6SJin Yao if (!strncmp(name, "cpu_", 4) && !is_hybrid) 94449afa7f6SJin Yao return NULL; 945cd82a32eSJiri Olsa 946cd82a32eSJiri Olsa /* 947cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 948cd82a32eSJiri Olsa * type value and format definitions. Load both right 949cd82a32eSJiri Olsa * now. 950cd82a32eSJiri Olsa */ 951cd82a32eSJiri Olsa if (pmu_format(name, &format)) 952cd82a32eSJiri Olsa return NULL; 953cd82a32eSJiri Olsa 95415b22ed3SAndi Kleen /* 95515b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 95615b22ed3SAndi Kleen */ 95715b22ed3SAndi Kleen if (pmu_type(name, &type)) 95815b22ed3SAndi Kleen return NULL; 95915b22ed3SAndi Kleen 9603fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 9613fded963SJiri Olsa return NULL; 9623fded963SJiri Olsa 963cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 964cd82a32eSJiri Olsa if (!pmu) 965cd82a32eSJiri Olsa return NULL; 966cd82a32eSJiri Olsa 9677ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 96854e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 96913d60ba0SKan Liang if (!pmu->name) 97013d60ba0SKan Liang goto err; 97113d60ba0SKan Liang 97213d60ba0SKan Liang alias_name = pmu_find_alias_name(name); 97313d60ba0SKan Liang if (alias_name) { 97413d60ba0SKan Liang pmu->alias_name = strdup(alias_name); 97513d60ba0SKan Liang if (!pmu->alias_name) 97613d60ba0SKan Liang goto err; 97713d60ba0SKan Liang } 97813d60ba0SKan Liang 97954e32dc0SGanapatrao Kulkarni pmu->type = type; 98066ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 98151d54847SJohn Garry if (pmu->is_uncore) 98251d54847SJohn Garry pmu->id = pmu_id(name); 98349afa7f6SJin Yao pmu->is_hybrid = is_hybrid; 98490a86bdeSJiri Olsa pmu->max_precise = pmu_max_precise(name); 98554e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 9864513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 98766ec1191SMark Rutland 988cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 989a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 9909fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 991cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 992a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 9939bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 994dc0a6202SAdrian Hunter 99544462430SJin Yao if (pmu->is_hybrid) 99644462430SJin Yao list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus); 99744462430SJin Yao 998dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 999dc0a6202SAdrian Hunter 1000cd82a32eSJiri Olsa return pmu; 100113d60ba0SKan Liang err: 100213d60ba0SKan Liang if (pmu->name) 100313d60ba0SKan Liang free(pmu->name); 100413d60ba0SKan Liang free(pmu); 100513d60ba0SKan Liang return NULL; 1006cd82a32eSJiri Olsa } 1007cd82a32eSJiri Olsa 1008b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 1009cd82a32eSJiri Olsa { 1010cd82a32eSJiri Olsa struct perf_pmu *pmu; 1011cd82a32eSJiri Olsa 101213d60ba0SKan Liang list_for_each_entry(pmu, &pmus, list) { 101313d60ba0SKan Liang if (!strcmp(pmu->name, name) || 101413d60ba0SKan Liang (pmu->alias_name && !strcmp(pmu->alias_name, name))) 1015cd82a32eSJiri Olsa return pmu; 101613d60ba0SKan Liang } 1017cd82a32eSJiri Olsa 1018cd82a32eSJiri Olsa return NULL; 1019cd82a32eSJiri Olsa } 1020cd82a32eSJiri Olsa 10213a50dc76SStephane Eranian struct perf_pmu *perf_pmu__find_by_type(unsigned int type) 10223a50dc76SStephane Eranian { 10233a50dc76SStephane Eranian struct perf_pmu *pmu; 10243a50dc76SStephane Eranian 10253a50dc76SStephane Eranian list_for_each_entry(pmu, &pmus, list) 10263a50dc76SStephane Eranian if (pmu->type == type) 10273a50dc76SStephane Eranian return pmu; 10283a50dc76SStephane Eranian 10293a50dc76SStephane Eranian return NULL; 10303a50dc76SStephane Eranian } 10313a50dc76SStephane Eranian 103250a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 103350a9667cSRobert Richter { 103450a9667cSRobert Richter /* 103550a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 103650a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 103750a9667cSRobert Richter */ 103850a9667cSRobert Richter if (!pmu) { 103950a9667cSRobert Richter pmu_read_sysfs(); 104050a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 104150a9667cSRobert Richter } 104250a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 104350a9667cSRobert Richter return pmu; 104450a9667cSRobert Richter return NULL; 104550a9667cSRobert Richter } 104650a9667cSRobert Richter 1047e76026bdSArnaldo Carvalho de Melo struct perf_pmu *evsel__find_pmu(struct evsel *evsel) 1048e12ee9f7SAdrian Hunter { 1049e12ee9f7SAdrian Hunter struct perf_pmu *pmu = NULL; 1050e12ee9f7SAdrian Hunter 1051e12ee9f7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1052e12ee9f7SAdrian Hunter if (pmu->type == evsel->core.attr.type) 1053e12ee9f7SAdrian Hunter break; 1054e12ee9f7SAdrian Hunter } 1055e12ee9f7SAdrian Hunter 1056e12ee9f7SAdrian Hunter return pmu; 1057e12ee9f7SAdrian Hunter } 1058e12ee9f7SAdrian Hunter 105939453ed5SArnaldo Carvalho de Melo bool evsel__is_aux_event(struct evsel *evsel) 1060e12ee9f7SAdrian Hunter { 1061e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 1062e12ee9f7SAdrian Hunter 1063e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 1064e12ee9f7SAdrian Hunter } 1065e12ee9f7SAdrian Hunter 1066b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 1067cd82a32eSJiri Olsa { 1068cd82a32eSJiri Olsa struct perf_pmu *pmu; 1069cd82a32eSJiri Olsa 1070cd82a32eSJiri Olsa /* 1071cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 1072cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 1073cd82a32eSJiri Olsa * the pmu format definitions. 1074cd82a32eSJiri Olsa */ 1075cd82a32eSJiri Olsa pmu = pmu_find(name); 1076cd82a32eSJiri Olsa if (pmu) 1077cd82a32eSJiri Olsa return pmu; 1078cd82a32eSJiri Olsa 1079cd82a32eSJiri Olsa return pmu_lookup(name); 1080cd82a32eSJiri Olsa } 1081cd82a32eSJiri Olsa 10825c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 108309ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 1084cd82a32eSJiri Olsa { 10855c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1086cd82a32eSJiri Olsa 1087cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 1088cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 1089cd82a32eSJiri Olsa return format; 1090cd82a32eSJiri Olsa 1091cd82a32eSJiri Olsa return NULL; 1092cd82a32eSJiri Olsa } 1093cd82a32eSJiri Olsa 109409ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 109509ff6071SAdrian Hunter { 109609ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 109709ff6071SAdrian Hunter __u64 bits = 0; 109809ff6071SAdrian Hunter int fbit; 109909ff6071SAdrian Hunter 110009ff6071SAdrian Hunter if (!format) 110109ff6071SAdrian Hunter return 0; 110209ff6071SAdrian Hunter 110309ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 110409ff6071SAdrian Hunter bits |= 1ULL << fbit; 110509ff6071SAdrian Hunter 110609ff6071SAdrian Hunter return bits; 110709ff6071SAdrian Hunter } 110809ff6071SAdrian Hunter 1109a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1110a1ac7de6SAdrian Hunter { 1111a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1112a1ac7de6SAdrian Hunter 1113a1ac7de6SAdrian Hunter if (!format) 1114a1ac7de6SAdrian Hunter return -1; 1115a1ac7de6SAdrian Hunter 1116a1ac7de6SAdrian Hunter return format->value; 1117a1ac7de6SAdrian Hunter } 1118a1ac7de6SAdrian Hunter 1119cd82a32eSJiri Olsa /* 1120dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 11214d39c89fSIngo Molnar * and unformatted value (value parameter). 1122cd82a32eSJiri Olsa */ 1123dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1124dc0a6202SAdrian Hunter bool zero) 1125cd82a32eSJiri Olsa { 1126cd82a32eSJiri Olsa unsigned long fbit, vbit; 1127cd82a32eSJiri Olsa 1128cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1129cd82a32eSJiri Olsa 1130cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1131cd82a32eSJiri Olsa continue; 1132cd82a32eSJiri Olsa 1133dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1134dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1135dc0a6202SAdrian Hunter else if (zero) 1136dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1137cd82a32eSJiri Olsa } 1138cd82a32eSJiri Olsa } 1139cd82a32eSJiri Olsa 11400efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 11410efe6b67SAdrian Hunter { 11421b9caa10SJiri Olsa int w; 11430efe6b67SAdrian Hunter 11441b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 11451b9caa10SJiri Olsa if (!w) 11461b9caa10SJiri Olsa return 0; 11471b9caa10SJiri Olsa if (w < 64) 11481b9caa10SJiri Olsa return (1ULL << w) - 1; 11491b9caa10SJiri Olsa return -1; 11500efe6b67SAdrian Hunter } 11510efe6b67SAdrian Hunter 1152cd82a32eSJiri Olsa /* 1153688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1154688d4dfcSCody P Schafer * in the remaining terms. 1155688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1156688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1157688d4dfcSCody P Schafer * in a config string) later on in the term list. 1158688d4dfcSCody P Schafer */ 1159688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1160688d4dfcSCody P Schafer struct list_head *head_terms, 1161688d4dfcSCody P Schafer __u64 *value) 1162688d4dfcSCody P Schafer { 1163688d4dfcSCody P Schafer struct parse_events_term *t; 1164688d4dfcSCody P Schafer 1165688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 11662a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 11672a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1168688d4dfcSCody P Schafer t->used = true; 1169688d4dfcSCody P Schafer *value = t->val.num; 1170688d4dfcSCody P Schafer return 0; 1171688d4dfcSCody P Schafer } 1172688d4dfcSCody P Schafer } 1173688d4dfcSCody P Schafer 1174bb963e16SNamhyung Kim if (verbose > 0) 1175688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1176688d4dfcSCody P Schafer 1177688d4dfcSCody P Schafer return -1; 1178688d4dfcSCody P Schafer } 1179688d4dfcSCody P Schafer 1180ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1181e64b020bSJiri Olsa { 1182e64b020bSJiri Olsa struct perf_pmu_format *format; 118311db4e29SMasami Hiramatsu char *str = NULL; 118411db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1185e64b020bSJiri Olsa unsigned i = 0; 1186e64b020bSJiri Olsa 1187ffeb883eSHe Kuang if (!formats) 1188e64b020bSJiri Olsa return NULL; 1189e64b020bSJiri Olsa 1190e64b020bSJiri Olsa /* sysfs exported terms */ 1191ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 119211db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 119311db4e29SMasami Hiramatsu goto error; 1194e64b020bSJiri Olsa 1195ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 119611db4e29SMasami Hiramatsu error: 1197ffeb883eSHe Kuang strbuf_release(&buf); 1198e64b020bSJiri Olsa 1199e64b020bSJiri Olsa return str; 1200e64b020bSJiri Olsa } 1201e64b020bSJiri Olsa 1202688d4dfcSCody P Schafer /* 1203cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 120488aca8d9SCody P Schafer * user input data - term parameter. 1205cd82a32eSJiri Olsa */ 12064ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 12074ac22b48SIan Rogers struct list_head *formats, 1208cd82a32eSJiri Olsa struct perf_event_attr *attr, 1209dc0a6202SAdrian Hunter struct parse_events_term *term, 1210688d4dfcSCody P Schafer struct list_head *head_terms, 1211e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1212cd82a32eSJiri Olsa { 12135c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1214cd82a32eSJiri Olsa __u64 *vp; 12150efe6b67SAdrian Hunter __u64 val, max_val; 1216cd82a32eSJiri Olsa 1217cd82a32eSJiri Olsa /* 1218688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1219688d4dfcSCody P Schafer * skip it in normal eval. 1220688d4dfcSCody P Schafer */ 1221688d4dfcSCody P Schafer if (term->used) 1222688d4dfcSCody P Schafer return 0; 1223688d4dfcSCody P Schafer 1224688d4dfcSCody P Schafer /* 1225cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1226cd82a32eSJiri Olsa * to be done for them. 1227cd82a32eSJiri Olsa */ 1228cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1229cd82a32eSJiri Olsa return 0; 1230cd82a32eSJiri Olsa 1231cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1232688d4dfcSCody P Schafer if (!format) { 1233ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 12344ac22b48SIan Rogers char *unknown_term; 12354ac22b48SIan Rogers char *help_msg; 1236ffeb883eSHe Kuang 12374ac22b48SIan Rogers if (asprintf(&unknown_term, 12384ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 12394ac22b48SIan Rogers term->config, pmu_name) < 0) 12404ac22b48SIan Rogers unknown_term = NULL; 12414ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 12424ac22b48SIan Rogers if (err) { 12436c191289SIan Rogers parse_events_error__handle(err, term->err_term, 12444ac22b48SIan Rogers unknown_term, 12454ac22b48SIan Rogers help_msg); 12464ac22b48SIan Rogers } else { 12474ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 12484ac22b48SIan Rogers free(unknown_term); 1249e64b020bSJiri Olsa } 12504ac22b48SIan Rogers free(pmu_term); 1251cd82a32eSJiri Olsa return -EINVAL; 1252688d4dfcSCody P Schafer } 1253cd82a32eSJiri Olsa 1254cd82a32eSJiri Olsa switch (format->value) { 1255cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1256cd82a32eSJiri Olsa vp = &attr->config; 1257cd82a32eSJiri Olsa break; 1258cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1259cd82a32eSJiri Olsa vp = &attr->config1; 1260cd82a32eSJiri Olsa break; 1261cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1262cd82a32eSJiri Olsa vp = &attr->config2; 1263cd82a32eSJiri Olsa break; 1264cd82a32eSJiri Olsa default: 1265cd82a32eSJiri Olsa return -EINVAL; 1266cd82a32eSJiri Olsa } 1267cd82a32eSJiri Olsa 126816fa7e82SJiri Olsa /* 1269688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1270688d4dfcSCody P Schafer * using event parameters. 127116fa7e82SJiri Olsa */ 127299e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 127399e7138eSJiri Olsa if (term->no_value && 127499e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 127599e7138eSJiri Olsa if (err) { 12766c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1277448d732cSIan Rogers strdup("no value assigned for term"), 1278448d732cSIan Rogers NULL); 127999e7138eSJiri Olsa } 128099e7138eSJiri Olsa return -EINVAL; 128199e7138eSJiri Olsa } 128299e7138eSJiri Olsa 1283688d4dfcSCody P Schafer val = term->val.num; 128499e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1285688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1286bb963e16SNamhyung Kim if (verbose > 0) { 1287688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1288688d4dfcSCody P Schafer term->config, term->val.str); 1289e64b020bSJiri Olsa } 1290e64b020bSJiri Olsa if (err) { 12916c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1292448d732cSIan Rogers strdup("expected numeric value"), 1293448d732cSIan Rogers NULL); 1294e64b020bSJiri Olsa } 1295688d4dfcSCody P Schafer return -EINVAL; 1296688d4dfcSCody P Schafer } 1297688d4dfcSCody P Schafer 1298688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1299688d4dfcSCody P Schafer return -EINVAL; 1300688d4dfcSCody P Schafer } else 1301688d4dfcSCody P Schafer return -EINVAL; 1302688d4dfcSCody P Schafer 13030efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 13040efe6b67SAdrian Hunter if (val > max_val) { 13050efe6b67SAdrian Hunter if (err) { 1306448d732cSIan Rogers char *err_str; 1307448d732cSIan Rogers 13086c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1309448d732cSIan Rogers asprintf(&err_str, 13100efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1311448d732cSIan Rogers (unsigned long long)max_val) < 0 1312448d732cSIan Rogers ? strdup("value too big for format") 1313448d732cSIan Rogers : err_str, 1314448d732cSIan Rogers NULL); 13150efe6b67SAdrian Hunter return -EINVAL; 13160efe6b67SAdrian Hunter } 13170efe6b67SAdrian Hunter /* 13180efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 13190efe6b67SAdrian Hunter * silently truncated. 13200efe6b67SAdrian Hunter */ 13210efe6b67SAdrian Hunter } 13220efe6b67SAdrian Hunter 1323688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1324cd82a32eSJiri Olsa return 0; 1325cd82a32eSJiri Olsa } 1326cd82a32eSJiri Olsa 13274ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1328cff7f956SJiri Olsa struct perf_event_attr *attr, 1329dc0a6202SAdrian Hunter struct list_head *head_terms, 1330e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1331cd82a32eSJiri Olsa { 13326cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1333cd82a32eSJiri Olsa 1334688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 13354ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1336e64b020bSJiri Olsa zero, err)) 1337cd82a32eSJiri Olsa return -EINVAL; 1338688d4dfcSCody P Schafer } 1339cd82a32eSJiri Olsa 1340cd82a32eSJiri Olsa return 0; 1341cd82a32eSJiri Olsa } 1342cd82a32eSJiri Olsa 1343cd82a32eSJiri Olsa /* 1344cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1345cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1346cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1347cd82a32eSJiri Olsa */ 1348cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1349e64b020bSJiri Olsa struct list_head *head_terms, 1350e64b020bSJiri Olsa struct parse_events_error *err) 1351cd82a32eSJiri Olsa { 1352dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1353dc0a6202SAdrian Hunter 1354cd82a32eSJiri Olsa attr->type = pmu->type; 13554ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 13564ac22b48SIan Rogers head_terms, zero, err); 1357cd82a32eSJiri Olsa } 1358cd82a32eSJiri Olsa 13595c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 13606cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1361a6146d50SZheng Yan { 13625c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1363a6146d50SZheng Yan char *name; 1364a6146d50SZheng Yan 1365a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1366a6146d50SZheng Yan return NULL; 1367a6146d50SZheng Yan 1368a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1369a6146d50SZheng Yan if (term->val.num != 1) 1370a6146d50SZheng Yan return NULL; 1371a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1372a6146d50SZheng Yan return NULL; 1373a6146d50SZheng Yan name = term->config; 1374a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1375a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1376a6146d50SZheng Yan return NULL; 1377a6146d50SZheng Yan name = term->val.str; 1378a6146d50SZheng Yan } else { 1379a6146d50SZheng Yan return NULL; 1380a6146d50SZheng Yan } 1381a6146d50SZheng Yan 1382a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1383a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1384a6146d50SZheng Yan return alias; 1385a6146d50SZheng Yan } 1386a6146d50SZheng Yan return NULL; 1387a6146d50SZheng Yan } 1388a6146d50SZheng Yan 1389410136f5SStephane Eranian 13901d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 13911d9e446bSJiri Olsa struct perf_pmu_info *info) 1392410136f5SStephane Eranian { 1393410136f5SStephane Eranian /* 1394410136f5SStephane Eranian * Only one term in event definition can 13951d9e446bSJiri Olsa * define unit, scale and snapshot, fail 13961d9e446bSJiri Olsa * if there's more than one. 1397410136f5SStephane Eranian */ 1398b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 13991d9e446bSJiri Olsa (info->scale && alias->scale) || 14001d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1401410136f5SStephane Eranian return -EINVAL; 1402410136f5SStephane Eranian 1403b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 14041d9e446bSJiri Olsa info->unit = alias->unit; 1405410136f5SStephane Eranian 1406410136f5SStephane Eranian if (alias->scale) 14071d9e446bSJiri Olsa info->scale = alias->scale; 14081d9e446bSJiri Olsa 14091d9e446bSJiri Olsa if (alias->snapshot) 14101d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1411410136f5SStephane Eranian 1412410136f5SStephane Eranian return 0; 1413410136f5SStephane Eranian } 1414410136f5SStephane Eranian 1415a6146d50SZheng Yan /* 1416a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1417a6146d50SZheng Yan * defined for the alias 1418a6146d50SZheng Yan */ 1419410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 142046441bdcSMatt Fleming struct perf_pmu_info *info) 1421a6146d50SZheng Yan { 14226cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 14235c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1424a6146d50SZheng Yan int ret; 1425a6146d50SZheng Yan 1426044330c1SMatt Fleming info->per_pkg = false; 1427044330c1SMatt Fleming 14288a398897SStephane Eranian /* 14298a398897SStephane Eranian * Mark unit and scale as not set 14308a398897SStephane Eranian * (different from default values, see below) 14318a398897SStephane Eranian */ 143246441bdcSMatt Fleming info->unit = NULL; 143346441bdcSMatt Fleming info->scale = 0.0; 14341d9e446bSJiri Olsa info->snapshot = false; 143537932c18SAndi Kleen info->metric_expr = NULL; 143696284814SAndi Kleen info->metric_name = NULL; 1437410136f5SStephane Eranian 1438a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1439a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1440a6146d50SZheng Yan if (!alias) 1441a6146d50SZheng Yan continue; 1442a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1443a6146d50SZheng Yan if (ret) 1444a6146d50SZheng Yan return ret; 1445410136f5SStephane Eranian 14461d9e446bSJiri Olsa ret = check_info_data(alias, info); 1447410136f5SStephane Eranian if (ret) 1448410136f5SStephane Eranian return ret; 1449410136f5SStephane Eranian 1450044330c1SMatt Fleming if (alias->per_pkg) 1451044330c1SMatt Fleming info->per_pkg = true; 145237932c18SAndi Kleen info->metric_expr = alias->metric_expr; 145396284814SAndi Kleen info->metric_name = alias->metric_name; 1454044330c1SMatt Fleming 1455e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 14561dc92556SIan Rogers parse_events_term__delete(term); 1457a6146d50SZheng Yan } 14588a398897SStephane Eranian 14598a398897SStephane Eranian /* 14608a398897SStephane Eranian * if no unit or scale found in aliases, then 14618a398897SStephane Eranian * set defaults as for evsel 14628a398897SStephane Eranian * unit cannot left to NULL 14638a398897SStephane Eranian */ 146446441bdcSMatt Fleming if (info->unit == NULL) 146546441bdcSMatt Fleming info->unit = ""; 14668a398897SStephane Eranian 146746441bdcSMatt Fleming if (info->scale == 0.0) 146846441bdcSMatt Fleming info->scale = 1.0; 14698a398897SStephane Eranian 1470a6146d50SZheng Yan return 0; 1471a6146d50SZheng Yan } 1472a6146d50SZheng Yan 1473cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1474cd82a32eSJiri Olsa int config, unsigned long *bits) 1475cd82a32eSJiri Olsa { 14765c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1477cd82a32eSJiri Olsa 1478cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1479cd82a32eSJiri Olsa if (!format) 1480cd82a32eSJiri Olsa return -ENOMEM; 1481cd82a32eSJiri Olsa 1482cd82a32eSJiri Olsa format->name = strdup(name); 1483cd82a32eSJiri Olsa format->value = config; 1484cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1485cd82a32eSJiri Olsa 1486cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1487cd82a32eSJiri Olsa return 0; 1488cd82a32eSJiri Olsa } 1489cd82a32eSJiri Olsa 1490cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1491cd82a32eSJiri Olsa { 1492cd82a32eSJiri Olsa long b; 1493cd82a32eSJiri Olsa 1494cd82a32eSJiri Olsa if (!to) 1495cd82a32eSJiri Olsa to = from; 1496cd82a32eSJiri Olsa 149715268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1498cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1499cd82a32eSJiri Olsa set_bit(b, bits); 1500cd82a32eSJiri Olsa } 1501dc098b35SAndi Kleen 1502d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1503d26383dcSNamhyung Kim { 1504d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1505d26383dcSNamhyung Kim 1506d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1507d26383dcSNamhyung Kim list_del(&fmt->list); 1508d26383dcSNamhyung Kim free(fmt->name); 1509d26383dcSNamhyung Kim free(fmt); 1510d26383dcSNamhyung Kim } 1511d26383dcSNamhyung Kim } 1512d26383dcSNamhyung Kim 1513aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1514aaea3617SCody P Schafer { 1515aaea3617SCody P Schafer if (b > a) 1516aaea3617SCody P Schafer return 0; 1517aaea3617SCody P Schafer return a - b; 1518aaea3617SCody P Schafer } 1519aaea3617SCody P Schafer 1520dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1521dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1522dc098b35SAndi Kleen { 1523aaea3617SCody P Schafer struct parse_events_term *term; 1524aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1525aaea3617SCody P Schafer 1526aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1527aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1528aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1529aaea3617SCody P Schafer ",%s=%s", term->config, 1530aaea3617SCody P Schafer term->val.str); 1531aaea3617SCody P Schafer } 1532aaea3617SCody P Schafer 1533aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1534aaea3617SCody P Schafer buf[used] = '/'; 1535aaea3617SCody P Schafer used++; 1536aaea3617SCody P Schafer } 1537aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1538aaea3617SCody P Schafer buf[used] = '\0'; 1539aaea3617SCody P Schafer used++; 1540aaea3617SCody P Schafer } else 1541aaea3617SCody P Schafer buf[len - 1] = '\0'; 1542aaea3617SCody P Schafer 1543dc098b35SAndi Kleen return buf; 1544dc098b35SAndi Kleen } 1545dc098b35SAndi Kleen 1546dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1547dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1548dc098b35SAndi Kleen { 1549dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1550dc098b35SAndi Kleen return buf; 1551dc098b35SAndi Kleen } 1552dc098b35SAndi Kleen 1553dd5f1036SAndi Kleen struct sevent { 155408e60ed1SAndi Kleen char *name; 155508e60ed1SAndi Kleen char *desc; 1556dd5f1036SAndi Kleen char *topic; 1557f2361024SAndi Kleen char *str; 1558f2361024SAndi Kleen char *pmu; 15597f372a63SAndi Kleen char *metric_expr; 156096284814SAndi Kleen char *metric_name; 1561ce0dc7d2SJohn Garry int is_cpu; 156208e60ed1SAndi Kleen }; 156308e60ed1SAndi Kleen 1564dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1565dc098b35SAndi Kleen { 1566dd5f1036SAndi Kleen const struct sevent *as = a; 1567dd5f1036SAndi Kleen const struct sevent *bs = b; 15680e0ae874SJin Yao int ret; 156908e60ed1SAndi Kleen 157008e60ed1SAndi Kleen /* Put extra events last */ 157108e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 157208e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1573dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1574dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1575dd5f1036SAndi Kleen 1576dd5f1036SAndi Kleen if (n) 1577dd5f1036SAndi Kleen return n; 1578dd5f1036SAndi Kleen } 1579ce0dc7d2SJohn Garry 1580ce0dc7d2SJohn Garry /* Order CPU core events to be first */ 1581ce0dc7d2SJohn Garry if (as->is_cpu != bs->is_cpu) 1582ce0dc7d2SJohn Garry return bs->is_cpu - as->is_cpu; 1583ce0dc7d2SJohn Garry 15840e0ae874SJin Yao ret = strcmp(as->name, bs->name); 15850e0ae874SJin Yao if (!ret) { 15860e0ae874SJin Yao if (as->pmu && bs->pmu) 15870e0ae874SJin Yao return strcmp(as->pmu, bs->pmu); 15880e0ae874SJin Yao } 15890e0ae874SJin Yao 15900e0ae874SJin Yao return ret; 159108e60ed1SAndi Kleen } 159208e60ed1SAndi Kleen 159308e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 159408e60ed1SAndi Kleen { 159508e60ed1SAndi Kleen int column = start; 159608e60ed1SAndi Kleen int n; 159708e60ed1SAndi Kleen 159808e60ed1SAndi Kleen while (*s) { 159908e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 160008e60ed1SAndi Kleen 160108e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 160208e60ed1SAndi Kleen printf("\n%*s", start, ""); 160308e60ed1SAndi Kleen column = start + corr; 160408e60ed1SAndi Kleen } 160508e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 160608e60ed1SAndi Kleen if (n <= 0) 160708e60ed1SAndi Kleen break; 160808e60ed1SAndi Kleen s += wlen; 160908e60ed1SAndi Kleen column += n; 161032858480SArnaldo Carvalho de Melo s = skip_spaces(s); 161108e60ed1SAndi Kleen } 1612dc098b35SAndi Kleen } 1613dc098b35SAndi Kleen 1614d504fae9SJohn Garry bool is_pmu_core(const char *name) 1615d504fae9SJohn Garry { 1616d504fae9SJohn Garry return !strcmp(name, "cpu") || is_arm_pmu_core(name); 1617d504fae9SJohn Garry } 1618d504fae9SJohn Garry 1619e0257a01SJohn Garry static bool pmu_alias_is_duplicate(struct sevent *alias_a, 1620e0257a01SJohn Garry struct sevent *alias_b) 1621e0257a01SJohn Garry { 1622e0257a01SJohn Garry /* Different names -> never duplicates */ 1623e0257a01SJohn Garry if (strcmp(alias_a->name, alias_b->name)) 1624e0257a01SJohn Garry return false; 1625e0257a01SJohn Garry 1626e0257a01SJohn Garry /* Don't remove duplicates for hybrid PMUs */ 1627e0257a01SJohn Garry if (perf_pmu__is_hybrid(alias_a->pmu) && 1628e0257a01SJohn Garry perf_pmu__is_hybrid(alias_b->pmu)) 1629e0257a01SJohn Garry return false; 1630e0257a01SJohn Garry 1631e0257a01SJohn Garry return true; 1632e0257a01SJohn Garry } 1633e0257a01SJohn Garry 1634c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 16350e0ae874SJin Yao bool long_desc, bool details_flag, bool deprecated, 16360e0ae874SJin Yao const char *pmu_name) 1637dc098b35SAndi Kleen { 1638dc098b35SAndi Kleen struct perf_pmu *pmu; 1639dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1640dc098b35SAndi Kleen char buf[1024]; 1641dc098b35SAndi Kleen int printed = 0; 1642dc098b35SAndi Kleen int len, j; 1643dd5f1036SAndi Kleen struct sevent *aliases; 164408e60ed1SAndi Kleen int numdesc = 0; 164561eb2eb4SAndi Kleen int columns = pager_get_columns(); 1646dd5f1036SAndi Kleen char *topic = NULL; 1647dc098b35SAndi Kleen 1648dc098b35SAndi Kleen pmu = NULL; 1649dc098b35SAndi Kleen len = 0; 165042634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1651dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1652dc098b35SAndi Kleen len++; 165342634bc7SAdrian Hunter if (pmu->selectable) 165442634bc7SAdrian Hunter len++; 165542634bc7SAdrian Hunter } 1656dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1657dc098b35SAndi Kleen if (!aliases) 16587e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1659dc098b35SAndi Kleen pmu = NULL; 1660dc098b35SAndi Kleen j = 0; 166142634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 16620e0ae874SJin Yao if (pmu_name && perf_pmu__is_hybrid(pmu->name) && 16630e0ae874SJin Yao strcmp(pmu_name, pmu->name)) { 16640e0ae874SJin Yao continue; 16650e0ae874SJin Yao } 16660e0ae874SJin Yao 1667dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 166808e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 166908e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 16700e0ae874SJin Yao bool is_cpu = is_pmu_core(pmu->name) || 16710e0ae874SJin Yao perf_pmu__is_hybrid(pmu->name); 1672dc098b35SAndi Kleen 1673a7f6c8c8SJin Yao if (alias->deprecated && !deprecated) 1674a7f6c8c8SJin Yao continue; 1675a7f6c8c8SJin Yao 1676dc098b35SAndi Kleen if (event_glob != NULL && 167738d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 167838d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 167967bdc35fSAndi Kleen event_glob)) || 168067bdc35fSAndi Kleen (alias->topic && 168167bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1682dc098b35SAndi Kleen continue; 16837e4772dcSArnaldo Carvalho de Melo 168408e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 16857e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 16867e4772dcSArnaldo Carvalho de Melo 168708e60ed1SAndi Kleen aliases[j].name = name; 168808e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 168908e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 169008e60ed1SAndi Kleen sizeof(buf), 169108e60ed1SAndi Kleen pmu, alias); 169208e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 169308e60ed1SAndi Kleen if (!aliases[j].name) 16947e4772dcSArnaldo Carvalho de Melo goto out_enomem; 169508e60ed1SAndi Kleen 1696c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1697c8d6828aSSukadev Bhattiprolu alias->desc; 1698dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1699f2361024SAndi Kleen aliases[j].str = alias->str; 1700f2361024SAndi Kleen aliases[j].pmu = pmu->name; 17017f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 170296284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1703ce0dc7d2SJohn Garry aliases[j].is_cpu = is_cpu; 1704dc098b35SAndi Kleen j++; 1705dc098b35SAndi Kleen } 1706fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1707fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 17087e4772dcSArnaldo Carvalho de Melo char *s; 17097e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 17107e4772dcSArnaldo Carvalho de Melo goto out_enomem; 171108e60ed1SAndi Kleen aliases[j].name = s; 171242634bc7SAdrian Hunter j++; 171342634bc7SAdrian Hunter } 171442634bc7SAdrian Hunter } 1715dc098b35SAndi Kleen len = j; 1716dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1717dc098b35SAndi Kleen for (j = 0; j < len; j++) { 171815b22ed3SAndi Kleen /* Skip duplicates */ 1719e0257a01SJohn Garry if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) 172015b22ed3SAndi Kleen continue; 17210e0ae874SJin Yao 1722dc098b35SAndi Kleen if (name_only) { 172308e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1724dc098b35SAndi Kleen continue; 1725dc098b35SAndi Kleen } 17261c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 172708e60ed1SAndi Kleen if (numdesc++ == 0) 172808e60ed1SAndi Kleen printf("\n"); 1729dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1730dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1731dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1732dd5f1036SAndi Kleen aliases[j].topic); 1733dd5f1036SAndi Kleen topic = aliases[j].topic; 1734dd5f1036SAndi Kleen } 173508e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 173608e60ed1SAndi Kleen printf("%*s", 8, "["); 173708e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 173808e60ed1SAndi Kleen printf("]\n"); 1739bf874fcfSAndi Kleen if (details_flag) { 17407f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 174196284814SAndi Kleen if (aliases[j].metric_name) 174296284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 17437f372a63SAndi Kleen if (aliases[j].metric_expr) 17447f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 17457f372a63SAndi Kleen putchar('\n'); 17467f372a63SAndi Kleen } 174708e60ed1SAndi Kleen } else 174808e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1749dc098b35SAndi Kleen printed++; 1750dc098b35SAndi Kleen } 1751dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1752dc098b35SAndi Kleen printf("\n"); 17537e4772dcSArnaldo Carvalho de Melo out_free: 17547e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 175508e60ed1SAndi Kleen zfree(&aliases[j].name); 17567e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 17577e4772dcSArnaldo Carvalho de Melo return; 17587e4772dcSArnaldo Carvalho de Melo 17597e4772dcSArnaldo Carvalho de Melo out_enomem: 17607e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 17617e4772dcSArnaldo Carvalho de Melo if (aliases) 17627e4772dcSArnaldo Carvalho de Melo goto out_free; 1763dc098b35SAndi Kleen } 17644cabc3d1SAndi Kleen 17654cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 17664cabc3d1SAndi Kleen { 17674cabc3d1SAndi Kleen struct perf_pmu *pmu; 17684cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 17694cabc3d1SAndi Kleen 17704cabc3d1SAndi Kleen pmu = NULL; 17714cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 17724cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 17734cabc3d1SAndi Kleen continue; 17744cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 17754cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 17764cabc3d1SAndi Kleen return true; 17774cabc3d1SAndi Kleen } 17784cabc3d1SAndi Kleen return false; 17794cabc3d1SAndi Kleen } 17807d4bdab5SAdrian Hunter 17817d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 17827d4bdab5SAdrian Hunter { 17837d4bdab5SAdrian Hunter char path[PATH_MAX]; 17847d4bdab5SAdrian Hunter const char *sysfs; 17857d4bdab5SAdrian Hunter 17867d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 17877d4bdab5SAdrian Hunter if (!sysfs) 17887d4bdab5SAdrian Hunter return NULL; 17897d4bdab5SAdrian Hunter 17907d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 17917d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 1792d9664582SAndi Kleen if (!file_available(path)) 17937d4bdab5SAdrian Hunter return NULL; 17947d4bdab5SAdrian Hunter return fopen(path, "r"); 17957d4bdab5SAdrian Hunter } 17967d4bdab5SAdrian Hunter 17977d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 17987d4bdab5SAdrian Hunter ...) 17997d4bdab5SAdrian Hunter { 18007d4bdab5SAdrian Hunter va_list args; 18017d4bdab5SAdrian Hunter FILE *file; 18027d4bdab5SAdrian Hunter int ret = EOF; 18037d4bdab5SAdrian Hunter 18047d4bdab5SAdrian Hunter va_start(args, fmt); 18057d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 18067d4bdab5SAdrian Hunter if (file) { 18077d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 18087d4bdab5SAdrian Hunter fclose(file); 18097d4bdab5SAdrian Hunter } 18107d4bdab5SAdrian Hunter va_end(args); 18117d4bdab5SAdrian Hunter return ret; 18127d4bdab5SAdrian Hunter } 18139fbc61f8SKan Liang 18149fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 18159fbc61f8SKan Liang { 18169fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 18179fbc61f8SKan Liang 18189fbc61f8SKan Liang if (!caps) 18199fbc61f8SKan Liang return -ENOMEM; 18209fbc61f8SKan Liang 18219fbc61f8SKan Liang caps->name = strdup(name); 18229fbc61f8SKan Liang if (!caps->name) 18239fbc61f8SKan Liang goto free_caps; 18249fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 18259fbc61f8SKan Liang if (!caps->value) 18269fbc61f8SKan Liang goto free_name; 18279fbc61f8SKan Liang list_add_tail(&caps->list, list); 18289fbc61f8SKan Liang return 0; 18299fbc61f8SKan Liang 18309fbc61f8SKan Liang free_name: 18319fbc61f8SKan Liang zfree(caps->name); 18329fbc61f8SKan Liang free_caps: 18339fbc61f8SKan Liang free(caps); 18349fbc61f8SKan Liang 18359fbc61f8SKan Liang return -ENOMEM; 18369fbc61f8SKan Liang } 18379fbc61f8SKan Liang 18389fbc61f8SKan Liang /* 18399fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 18409fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 18419fbc61f8SKan Liang * Return the number of capabilities 18429fbc61f8SKan Liang */ 18439fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 18449fbc61f8SKan Liang { 18459fbc61f8SKan Liang struct stat st; 18469fbc61f8SKan Liang char caps_path[PATH_MAX]; 18479fbc61f8SKan Liang const char *sysfs = sysfs__mountpoint(); 18489fbc61f8SKan Liang DIR *caps_dir; 18499fbc61f8SKan Liang struct dirent *evt_ent; 18503339ec44SRavi Bangoria 18513339ec44SRavi Bangoria if (pmu->caps_initialized) 18523339ec44SRavi Bangoria return pmu->nr_caps; 18533339ec44SRavi Bangoria 18543339ec44SRavi Bangoria pmu->nr_caps = 0; 18559fbc61f8SKan Liang 18569fbc61f8SKan Liang if (!sysfs) 18579fbc61f8SKan Liang return -1; 18589fbc61f8SKan Liang 18599fbc61f8SKan Liang snprintf(caps_path, PATH_MAX, 18609fbc61f8SKan Liang "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name); 18619fbc61f8SKan Liang 18623339ec44SRavi Bangoria if (stat(caps_path, &st) < 0) { 18633339ec44SRavi Bangoria pmu->caps_initialized = true; 18649fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 18653339ec44SRavi Bangoria } 18669fbc61f8SKan Liang 18679fbc61f8SKan Liang caps_dir = opendir(caps_path); 18689fbc61f8SKan Liang if (!caps_dir) 18699fbc61f8SKan Liang return -EINVAL; 18709fbc61f8SKan Liang 18719fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 18729fbc61f8SKan Liang char path[PATH_MAX + NAME_MAX + 1]; 18739fbc61f8SKan Liang char *name = evt_ent->d_name; 18749fbc61f8SKan Liang char value[128]; 18759fbc61f8SKan Liang FILE *file; 18769fbc61f8SKan Liang 18779fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 18789fbc61f8SKan Liang continue; 18799fbc61f8SKan Liang 18809fbc61f8SKan Liang snprintf(path, sizeof(path), "%s/%s", caps_path, name); 18819fbc61f8SKan Liang 18829fbc61f8SKan Liang file = fopen(path, "r"); 18839fbc61f8SKan Liang if (!file) 18849fbc61f8SKan Liang continue; 18859fbc61f8SKan Liang 18869fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 18879fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 18889fbc61f8SKan Liang fclose(file); 18899fbc61f8SKan Liang continue; 18909fbc61f8SKan Liang } 18919fbc61f8SKan Liang 18923339ec44SRavi Bangoria pmu->nr_caps++; 18939fbc61f8SKan Liang fclose(file); 18949fbc61f8SKan Liang } 18959fbc61f8SKan Liang 18969fbc61f8SKan Liang closedir(caps_dir); 18979fbc61f8SKan Liang 18983339ec44SRavi Bangoria pmu->caps_initialized = true; 18993339ec44SRavi Bangoria return pmu->nr_caps; 19009fbc61f8SKan Liang } 1901e4064776SJin Yao 1902e4064776SJin Yao void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 19038e8bbfb3SIan Rogers const char *name) 1904e4064776SJin Yao { 1905e4064776SJin Yao struct perf_pmu_format *format; 1906e4064776SJin Yao __u64 masks = 0, bits; 1907e4064776SJin Yao char buf[100]; 1908e4064776SJin Yao unsigned int i; 1909e4064776SJin Yao 1910e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1911e4064776SJin Yao if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG) 1912e4064776SJin Yao continue; 1913e4064776SJin Yao 1914e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1915e4064776SJin Yao masks |= 1ULL << i; 1916e4064776SJin Yao } 1917e4064776SJin Yao 1918e4064776SJin Yao /* 1919e4064776SJin Yao * Kernel doesn't export any valid format bits. 1920e4064776SJin Yao */ 1921e4064776SJin Yao if (masks == 0) 1922e4064776SJin Yao return; 1923e4064776SJin Yao 1924e4064776SJin Yao bits = config & ~masks; 1925e4064776SJin Yao if (bits == 0) 1926e4064776SJin Yao return; 1927e4064776SJin Yao 1928e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1929e4064776SJin Yao 1930e4064776SJin Yao pr_warning("WARNING: event '%s' not valid (bits %s of config " 1931e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1932e4064776SJin Yao name ?: "N/A", buf, config); 1933e4064776SJin Yao } 1934c5a26ea4SJin Yao 1935c5a26ea4SJin Yao bool perf_pmu__has_hybrid(void) 1936c5a26ea4SJin Yao { 1937c5a26ea4SJin Yao if (!hybrid_scanned) { 1938c5a26ea4SJin Yao hybrid_scanned = true; 1939c5a26ea4SJin Yao perf_pmu__scan(NULL); 1940c5a26ea4SJin Yao } 1941c5a26ea4SJin Yao 1942c5a26ea4SJin Yao return !list_empty(&perf_pmu__hybrid_pmus); 1943c5a26ea4SJin Yao } 1944c47a5599SJin Yao 1945c47a5599SJin Yao int perf_pmu__match(char *pattern, char *name, char *tok) 1946c47a5599SJin Yao { 194713d60ba0SKan Liang if (!name) 194813d60ba0SKan Liang return -1; 194913d60ba0SKan Liang 1950c47a5599SJin Yao if (fnmatch(pattern, name, 0)) 1951c47a5599SJin Yao return -1; 1952c47a5599SJin Yao 1953c47a5599SJin Yao if (tok && !perf_pmu__valid_suffix(name, tok)) 1954c47a5599SJin Yao return -1; 1955c47a5599SJin Yao 1956c47a5599SJin Yao return 0; 1957c47a5599SJin Yao } 19581d3351e6SJin Yao 19591d3351e6SJin Yao int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus, 19601d3351e6SJin Yao struct perf_cpu_map **mcpus_ptr, 19611d3351e6SJin Yao struct perf_cpu_map **ucpus_ptr) 19621d3351e6SJin Yao { 19631d3351e6SJin Yao struct perf_cpu_map *pmu_cpus = pmu->cpus; 19641d3351e6SJin Yao struct perf_cpu_map *matched_cpus, *unmatched_cpus; 19656a12a63eSIan Rogers struct perf_cpu cpu; 19666a12a63eSIan Rogers int i, matched_nr = 0, unmatched_nr = 0; 19671d3351e6SJin Yao 19681d3351e6SJin Yao matched_cpus = perf_cpu_map__default_new(); 19691d3351e6SJin Yao if (!matched_cpus) 19701d3351e6SJin Yao return -1; 19711d3351e6SJin Yao 19721d3351e6SJin Yao unmatched_cpus = perf_cpu_map__default_new(); 19731d3351e6SJin Yao if (!unmatched_cpus) { 19741d3351e6SJin Yao perf_cpu_map__put(matched_cpus); 19751d3351e6SJin Yao return -1; 19761d3351e6SJin Yao } 19771d3351e6SJin Yao 19786a12a63eSIan Rogers perf_cpu_map__for_each_cpu(cpu, i, cpus) { 19796a12a63eSIan Rogers if (!perf_cpu_map__has(pmu_cpus, cpu)) 19806a12a63eSIan Rogers unmatched_cpus->map[unmatched_nr++] = cpu; 19811d3351e6SJin Yao else 19826a12a63eSIan Rogers matched_cpus->map[matched_nr++] = cpu; 19831d3351e6SJin Yao } 19841d3351e6SJin Yao 19851d3351e6SJin Yao unmatched_cpus->nr = unmatched_nr; 19861d3351e6SJin Yao matched_cpus->nr = matched_nr; 19871d3351e6SJin Yao *mcpus_ptr = matched_cpus; 19881d3351e6SJin Yao *ucpus_ptr = unmatched_cpus; 19891d3351e6SJin Yao return 0; 19901d3351e6SJin Yao } 1991