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> 7cd82a32eSJiri Olsa #include <sys/types.h> 8c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h> 97a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 10cd82a32eSJiri Olsa #include <unistd.h> 11cd82a32eSJiri Olsa #include <stdio.h> 12dc0a6202SAdrian Hunter #include <stdbool.h> 13cd82a32eSJiri Olsa #include <dirent.h> 14cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 15410136f5SStephane Eranian #include <locale.h> 16c47a5599SJin Yao #include <fnmatch.h> 17acef233bSJing Zhang #include <math.h> 185e51b0bbSArnaldo Carvalho de Melo #include "debug.h" 19e12ee9f7SAdrian Hunter #include "evsel.h" 20cd82a32eSJiri Olsa #include "pmu.h" 21336b92daSRavi Bangoria #include "pmus.h" 223d88aec0SIan Rogers #include "pmu-bison.h" 233d88aec0SIan Rogers #include "pmu-flex.h" 24cd82a32eSJiri Olsa #include "parse-events.h" 25e5c6109fSIan Rogers #include "print-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" 306593f019SJames Clark #include "util/evsel_config.h" 31cd82a32eSJiri Olsa 32e46fc8d9SArnaldo Carvalho de Melo struct perf_pmu perf_pmu__fake; 33e46fc8d9SArnaldo Carvalho de Melo 34fe13d43dSIan Rogers /** 35fe13d43dSIan Rogers * struct perf_pmu_format - Values from a format file read from 36fe13d43dSIan Rogers * <sysfs>/devices/cpu/format/ held in struct perf_pmu. 37fe13d43dSIan Rogers * 38fe13d43dSIan Rogers * For example, the contents of <sysfs>/devices/cpu/format/event may be 39fe13d43dSIan Rogers * "config:0-7" and will be represented here as name="event", 40fe13d43dSIan Rogers * value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set. 41fe13d43dSIan Rogers */ 42ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 43fe13d43dSIan Rogers /** @name: The modifier/file name. */ 44ab1bf653SArnaldo Carvalho de Melo char *name; 45fe13d43dSIan Rogers /** 46fe13d43dSIan Rogers * @value : Which config value the format relates to. Supported values 47fe13d43dSIan Rogers * are from PERF_PMU_FORMAT_VALUE_CONFIG to 48fe13d43dSIan Rogers * PERF_PMU_FORMAT_VALUE_CONFIG_END. 49fe13d43dSIan Rogers */ 50ab1bf653SArnaldo Carvalho de Melo int value; 51fe13d43dSIan Rogers /** @bits: Which config bits are set by this format value. */ 52ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 53fe13d43dSIan Rogers /** @list: Element on list within struct perf_pmu. */ 54ab1bf653SArnaldo Carvalho de Melo struct list_head list; 55ab1bf653SArnaldo Carvalho de Melo }; 56ab1bf653SArnaldo Carvalho de Melo 57cd82a32eSJiri Olsa /* 58cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 59cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 60cd82a32eSJiri Olsa */ 61e293a5e8SNamhyung Kim int perf_pmu__format_parse(int dirfd, struct list_head *head) 62cd82a32eSJiri Olsa { 63cd82a32eSJiri Olsa struct dirent *evt_ent; 64cd82a32eSJiri Olsa DIR *format_dir; 65cd82a32eSJiri Olsa int ret = 0; 66cd82a32eSJiri Olsa 67e293a5e8SNamhyung Kim format_dir = fdopendir(dirfd); 68cd82a32eSJiri Olsa if (!format_dir) 69cd82a32eSJiri Olsa return -EINVAL; 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 72cd82a32eSJiri Olsa char *name = evt_ent->d_name; 73e293a5e8SNamhyung Kim int fd; 743d88aec0SIan Rogers void *scanner; 753d88aec0SIan Rogers FILE *file; 76cd82a32eSJiri Olsa 77cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 78cd82a32eSJiri Olsa continue; 79cd82a32eSJiri Olsa 80cd82a32eSJiri Olsa 81cd82a32eSJiri Olsa ret = -EINVAL; 82e293a5e8SNamhyung Kim fd = openat(dirfd, name, O_RDONLY); 83e293a5e8SNamhyung Kim if (fd < 0) 84cd82a32eSJiri Olsa break; 85cd82a32eSJiri Olsa 863d88aec0SIan Rogers file = fdopen(fd, "r"); 873d88aec0SIan Rogers if (!file) { 883d88aec0SIan Rogers close(fd); 893d88aec0SIan Rogers break; 903d88aec0SIan Rogers } 913d88aec0SIan Rogers 923d88aec0SIan Rogers ret = perf_pmu_lex_init(&scanner); 933d88aec0SIan Rogers if (ret) { 943d88aec0SIan Rogers fclose(file); 953d88aec0SIan Rogers break; 963d88aec0SIan Rogers } 973d88aec0SIan Rogers 983d88aec0SIan Rogers perf_pmu_set_in(file, scanner); 993d88aec0SIan Rogers ret = perf_pmu_parse(head, name, scanner); 1003d88aec0SIan Rogers perf_pmu_lex_destroy(scanner); 1013d88aec0SIan Rogers fclose(file); 102cd82a32eSJiri Olsa } 103cd82a32eSJiri Olsa 104cd82a32eSJiri Olsa closedir(format_dir); 105cd82a32eSJiri Olsa return ret; 106cd82a32eSJiri Olsa } 107cd82a32eSJiri Olsa 108cd82a32eSJiri Olsa /* 109cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 110cd82a32eSJiri Olsa * located at: 111cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 112cd82a32eSJiri Olsa */ 113e293a5e8SNamhyung Kim static int pmu_format(int dirfd, const char *name, struct list_head *format) 114cd82a32eSJiri Olsa { 115e293a5e8SNamhyung Kim int fd; 116cd82a32eSJiri Olsa 117e293a5e8SNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "format", O_DIRECTORY); 118e293a5e8SNamhyung Kim if (fd < 0) 119d9664582SAndi Kleen return 0; 120cd82a32eSJiri Olsa 121e293a5e8SNamhyung Kim /* it'll close the fd */ 122e293a5e8SNamhyung Kim if (perf_pmu__format_parse(fd, format)) 123cd82a32eSJiri Olsa return -1; 124cd82a32eSJiri Olsa 125cd82a32eSJiri Olsa return 0; 126cd82a32eSJiri Olsa } 127cd82a32eSJiri Olsa 128a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 129d02fc6bcSAndi Kleen { 130d02fc6bcSAndi Kleen char *lc; 131d02fc6bcSAndi Kleen int ret = 0; 132d02fc6bcSAndi Kleen 133d02fc6bcSAndi Kleen /* 134d02fc6bcSAndi Kleen * save current locale 135d02fc6bcSAndi Kleen */ 136d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 137d02fc6bcSAndi Kleen 138d02fc6bcSAndi Kleen /* 139d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 140d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 141d02fc6bcSAndi Kleen * call below. 142d02fc6bcSAndi Kleen */ 143d02fc6bcSAndi Kleen lc = strdup(lc); 144d02fc6bcSAndi Kleen if (!lc) { 145d02fc6bcSAndi Kleen ret = -ENOMEM; 146d02fc6bcSAndi Kleen goto out; 147d02fc6bcSAndi Kleen } 148d02fc6bcSAndi Kleen 149d02fc6bcSAndi Kleen /* 150d02fc6bcSAndi Kleen * force to C locale to ensure kernel 151d02fc6bcSAndi Kleen * scale string is converted correctly. 152d02fc6bcSAndi Kleen * kernel uses default C locale. 153d02fc6bcSAndi Kleen */ 154d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 155d02fc6bcSAndi Kleen 156d02fc6bcSAndi Kleen *sval = strtod(scale, end); 157d02fc6bcSAndi Kleen 158d02fc6bcSAndi Kleen out: 159d02fc6bcSAndi Kleen /* restore locale */ 160d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 161d02fc6bcSAndi Kleen free(lc); 162d02fc6bcSAndi Kleen return ret; 163d02fc6bcSAndi Kleen } 164d02fc6bcSAndi Kleen 165e293a5e8SNamhyung Kim static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, int dirfd, char *name) 166410136f5SStephane Eranian { 167410136f5SStephane Eranian struct stat st; 168410136f5SStephane Eranian ssize_t sret; 169410136f5SStephane Eranian char scale[128]; 170410136f5SStephane Eranian int fd, ret = -1; 171410136f5SStephane Eranian char path[PATH_MAX]; 172410136f5SStephane Eranian 173e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.scale", name); 174410136f5SStephane Eranian 175e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 176410136f5SStephane Eranian if (fd == -1) 177410136f5SStephane Eranian return -1; 178410136f5SStephane Eranian 179410136f5SStephane Eranian if (fstat(fd, &st) < 0) 180410136f5SStephane Eranian goto error; 181410136f5SStephane Eranian 182410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 183410136f5SStephane Eranian if (sret < 0) 184410136f5SStephane Eranian goto error; 185410136f5SStephane Eranian 1869ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1879ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1889ecae065SMadhavan Srinivasan else 189410136f5SStephane Eranian scale[sret] = '\0'; 1909ecae065SMadhavan Srinivasan 191a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 192410136f5SStephane Eranian error: 193410136f5SStephane Eranian close(fd); 194410136f5SStephane Eranian return ret; 195410136f5SStephane Eranian } 196410136f5SStephane Eranian 197e293a5e8SNamhyung Kim static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, int dirfd, char *name) 198410136f5SStephane Eranian { 199410136f5SStephane Eranian char path[PATH_MAX]; 200410136f5SStephane Eranian ssize_t sret; 201410136f5SStephane Eranian int fd; 202410136f5SStephane Eranian 203e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.unit", name); 204410136f5SStephane Eranian 205e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 206410136f5SStephane Eranian if (fd == -1) 207410136f5SStephane Eranian return -1; 208410136f5SStephane Eranian 209410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 210410136f5SStephane Eranian if (sret < 0) 211410136f5SStephane Eranian goto error; 212410136f5SStephane Eranian 213410136f5SStephane Eranian close(fd); 214410136f5SStephane Eranian 2159ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 2169ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 2179ecae065SMadhavan Srinivasan else 218410136f5SStephane Eranian alias->unit[sret] = '\0'; 219410136f5SStephane Eranian 220410136f5SStephane Eranian return 0; 221410136f5SStephane Eranian error: 222410136f5SStephane Eranian close(fd); 223410136f5SStephane Eranian alias->unit[0] = '\0'; 224410136f5SStephane Eranian return -1; 225410136f5SStephane Eranian } 226410136f5SStephane Eranian 227044330c1SMatt Fleming static int 228e293a5e8SNamhyung Kim perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, int dirfd, char *name) 229044330c1SMatt Fleming { 230044330c1SMatt Fleming char path[PATH_MAX]; 231044330c1SMatt Fleming int fd; 232044330c1SMatt Fleming 233e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.per-pkg", name); 234044330c1SMatt Fleming 235e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 236044330c1SMatt Fleming if (fd == -1) 237044330c1SMatt Fleming return -1; 238044330c1SMatt Fleming 239044330c1SMatt Fleming close(fd); 240044330c1SMatt Fleming 241044330c1SMatt Fleming alias->per_pkg = true; 242044330c1SMatt Fleming return 0; 243044330c1SMatt Fleming } 244044330c1SMatt Fleming 2451d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 246e293a5e8SNamhyung Kim int dirfd, char *name) 2471d9e446bSJiri Olsa { 2481d9e446bSJiri Olsa char path[PATH_MAX]; 2491d9e446bSJiri Olsa int fd; 2501d9e446bSJiri Olsa 251e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.snapshot", name); 2521d9e446bSJiri Olsa 253e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 2541d9e446bSJiri Olsa if (fd == -1) 2551d9e446bSJiri Olsa return -1; 2561d9e446bSJiri Olsa 2571d9e446bSJiri Olsa alias->snapshot = true; 2581d9e446bSJiri Olsa close(fd); 2591d9e446bSJiri Olsa return 0; 2601d9e446bSJiri Olsa } 2611d9e446bSJiri Olsa 2626dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2636dde6429SThomas Richter char **new_str) 2646dde6429SThomas Richter { 2656dde6429SThomas Richter if (!*old_str) 2666dde6429SThomas Richter goto set_new; 2676dde6429SThomas Richter 2686dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2696dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2706dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2716dde6429SThomas Richter name, field); 2726dde6429SThomas Richter zfree(old_str); 2736dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2746dde6429SThomas Richter return; 2756dde6429SThomas Richter set_new: 2766dde6429SThomas Richter *old_str = *new_str; 2776dde6429SThomas Richter *new_str = NULL; 2786dde6429SThomas Richter } 2796dde6429SThomas Richter 2806dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2816dde6429SThomas Richter struct perf_pmu_alias *newalias) 2826dde6429SThomas Richter { 2836dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2846dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2856dde6429SThomas Richter &newalias->long_desc); 2866dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2876dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2886dde6429SThomas Richter old->scale = newalias->scale; 2896dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2906dde6429SThomas Richter old->snapshot = newalias->snapshot; 2916dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2926dde6429SThomas Richter } 2936dde6429SThomas Richter 2946dde6429SThomas Richter /* Delete an alias entry. */ 29522fe5a25SNamhyung Kim void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2966dde6429SThomas Richter { 2976dde6429SThomas Richter zfree(&newalias->name); 2986dde6429SThomas Richter zfree(&newalias->desc); 2996dde6429SThomas Richter zfree(&newalias->long_desc); 3006dde6429SThomas Richter zfree(&newalias->topic); 3016dde6429SThomas Richter zfree(&newalias->str); 30232705de7SJin Yao zfree(&newalias->pmu_name); 3036dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 3046dde6429SThomas Richter free(newalias); 3056dde6429SThomas Richter } 3066dde6429SThomas Richter 307eec11310SNamhyung Kim static void perf_pmu__del_aliases(struct perf_pmu *pmu) 308eec11310SNamhyung Kim { 309eec11310SNamhyung Kim struct perf_pmu_alias *alias, *tmp; 310eec11310SNamhyung Kim 311eec11310SNamhyung Kim list_for_each_entry_safe(alias, tmp, &pmu->aliases, list) { 312eec11310SNamhyung Kim list_del(&alias->list); 313eec11310SNamhyung Kim perf_pmu_free_alias(alias); 314eec11310SNamhyung Kim } 315eec11310SNamhyung Kim } 316eec11310SNamhyung Kim 3176dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 3186dde6429SThomas Richter * present merge both of them to combine all information. 3196dde6429SThomas Richter */ 3206dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 3216dde6429SThomas Richter struct list_head *alist) 3226dde6429SThomas Richter { 3236dde6429SThomas Richter struct perf_pmu_alias *a; 3246dde6429SThomas Richter 3256dde6429SThomas Richter list_for_each_entry(a, alist, list) { 3266dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 32732705de7SJin Yao if (newalias->pmu_name && a->pmu_name && 32832705de7SJin Yao !strcasecmp(newalias->pmu_name, a->pmu_name)) { 32932705de7SJin Yao continue; 33032705de7SJin Yao } 3316dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 3326dde6429SThomas Richter perf_pmu_free_alias(newalias); 3336dde6429SThomas Richter return true; 3346dde6429SThomas Richter } 3356dde6429SThomas Richter } 3366dde6429SThomas Richter return false; 3376dde6429SThomas Richter } 3386dde6429SThomas Richter 339e293a5e8SNamhyung Kim static int __perf_pmu__new_alias(struct list_head *list, int dirfd, char *name, 34047f572aaSIan Rogers char *desc, char *val, const struct pmu_event *pe) 341a6146d50SZheng Yan { 3420c24d6fbSThomas Richter struct parse_events_term *term; 3435c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 344a6146d50SZheng Yan int ret; 3450c24d6fbSThomas Richter char newval[256]; 346330f40a0SIan Rogers const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL; 347bd680861SIan Rogers bool deprecated = false, perpkg = false; 348eab35953SJin Yao 349eab35953SJin Yao if (pe) { 350330f40a0SIan Rogers long_desc = pe->long_desc; 351330f40a0SIan Rogers topic = pe->topic; 352330f40a0SIan Rogers unit = pe->unit; 353bd680861SIan Rogers perpkg = pe->perpkg; 3549ed8b7dcSIan Rogers deprecated = pe->deprecated; 355330f40a0SIan Rogers pmu_name = pe->pmu; 356eab35953SJin Yao } 357a6146d50SZheng Yan 358a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 359a6146d50SZheng Yan if (!alias) 360a6146d50SZheng Yan return -ENOMEM; 361a6146d50SZheng Yan 362a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 363410136f5SStephane Eranian alias->scale = 1.0; 364410136f5SStephane Eranian alias->unit[0] = '\0'; 365bd680861SIan Rogers alias->per_pkg = perpkg; 36684530920SStephane Eranian alias->snapshot = false; 3679ed8b7dcSIan Rogers alias->deprecated = deprecated; 368410136f5SStephane Eranian 36970c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 370a6146d50SZheng Yan if (ret) { 37170c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 372a6146d50SZheng Yan free(alias); 373a6146d50SZheng Yan return ret; 374a6146d50SZheng Yan } 375a6146d50SZheng Yan 3760c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3770c24d6fbSThomas Richter * platforms have terms specified as 3780c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3790c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3800c24d6fbSThomas Richter * 3810c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3820c24d6fbSThomas Richter */ 3830c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3840c24d6fbSThomas Richter ret = 0; 3850c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3860c24d6fbSThomas Richter if (ret) 3870c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3880c24d6fbSThomas Richter ","); 3890c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3900c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3910c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3920c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3930c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3940c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3950c24d6fbSThomas Richter } 3960c24d6fbSThomas Richter 397a6146d50SZheng Yan alias->name = strdup(name); 398e293a5e8SNamhyung Kim if (dirfd >= 0) { 399410136f5SStephane Eranian /* 400410136f5SStephane Eranian * load unit name and scale if available 401410136f5SStephane Eranian */ 402e293a5e8SNamhyung Kim perf_pmu__parse_unit(alias, dirfd, name); 403e293a5e8SNamhyung Kim perf_pmu__parse_scale(alias, dirfd, name); 404e293a5e8SNamhyung Kim perf_pmu__parse_per_pkg(alias, dirfd, name); 405e293a5e8SNamhyung Kim perf_pmu__parse_snapshot(alias, dirfd, name); 40670c646e0SSukadev Bhattiprolu } 407410136f5SStephane Eranian 40808e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 409c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 410c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 411dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 412fedb2b51SAndi Kleen if (unit) { 413330f40a0SIan Rogers if (perf_pmu__convert_scale(unit, (char **)&unit, &alias->scale) < 0) 414fedb2b51SAndi Kleen return -1; 415fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 416fedb2b51SAndi Kleen } 4170c24d6fbSThomas Richter alias->str = strdup(newval); 41832705de7SJin Yao alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; 419f2361024SAndi Kleen 4206dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 421a6146d50SZheng Yan list_add_tail(&alias->list, list); 422410136f5SStephane Eranian 423a6146d50SZheng Yan return 0; 424a6146d50SZheng Yan } 425a6146d50SZheng Yan 426e293a5e8SNamhyung Kim static int perf_pmu__new_alias(struct list_head *list, int dirfd, char *name, FILE *file) 42770c646e0SSukadev Bhattiprolu { 42870c646e0SSukadev Bhattiprolu char buf[256]; 42970c646e0SSukadev Bhattiprolu int ret; 43070c646e0SSukadev Bhattiprolu 43170c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 43270c646e0SSukadev Bhattiprolu if (ret == 0) 43370c646e0SSukadev Bhattiprolu return -EINVAL; 43470c646e0SSukadev Bhattiprolu 43570c646e0SSukadev Bhattiprolu buf[ret] = 0; 43670c646e0SSukadev Bhattiprolu 437ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 43813c230abSArnaldo Carvalho de Melo strim(buf); 439ea23ac73SThomas Richter 440e293a5e8SNamhyung Kim return __perf_pmu__new_alias(list, dirfd, name, NULL, buf, NULL); 44170c646e0SSukadev Bhattiprolu } 44270c646e0SSukadev Bhattiprolu 44346441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 44446441bdcSMatt Fleming { 44546441bdcSMatt Fleming size_t len; 44646441bdcSMatt Fleming 44746441bdcSMatt Fleming len = strlen(name); 44846441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 44946441bdcSMatt Fleming return true; 45046441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 45146441bdcSMatt Fleming return true; 452044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 453044330c1SMatt Fleming return true; 4541d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4551d9e446bSJiri Olsa return true; 45646441bdcSMatt Fleming 45746441bdcSMatt Fleming return false; 45846441bdcSMatt Fleming } 45946441bdcSMatt Fleming 460a6146d50SZheng Yan /* 461a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 462a6146d50SZheng Yan * specified in 'dir' parameter. 463a6146d50SZheng Yan */ 464e293a5e8SNamhyung Kim static int pmu_aliases_parse(int dirfd, struct list_head *head) 465a6146d50SZheng Yan { 466a6146d50SZheng Yan struct dirent *evt_ent; 467a6146d50SZheng Yan DIR *event_dir; 468e293a5e8SNamhyung Kim int fd; 469a6146d50SZheng Yan 470e293a5e8SNamhyung Kim event_dir = fdopendir(dirfd); 471a6146d50SZheng Yan if (!event_dir) 472a6146d50SZheng Yan return -EINVAL; 473a6146d50SZheng Yan 474940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 475a6146d50SZheng Yan char *name = evt_ent->d_name; 476a6146d50SZheng Yan FILE *file; 477a6146d50SZheng Yan 478a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 479a6146d50SZheng Yan continue; 480a6146d50SZheng Yan 481410136f5SStephane Eranian /* 48246441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 483410136f5SStephane Eranian */ 48446441bdcSMatt Fleming if (pmu_alias_info_file(name)) 485410136f5SStephane Eranian continue; 486410136f5SStephane Eranian 487e293a5e8SNamhyung Kim fd = openat(dirfd, name, O_RDONLY); 4880ea8920eSIan Rogers if (fd == -1) { 4890ea8920eSIan Rogers pr_debug("Cannot open %s\n", name); 4900ea8920eSIan Rogers continue; 4910ea8920eSIan Rogers } 492e293a5e8SNamhyung Kim file = fdopen(fd, "r"); 493940db6dcSAndi Kleen if (!file) { 4940ea8920eSIan Rogers close(fd); 495940db6dcSAndi Kleen continue; 496940db6dcSAndi Kleen } 497410136f5SStephane Eranian 498e293a5e8SNamhyung Kim if (perf_pmu__new_alias(head, dirfd, name, file) < 0) 499940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 500a6146d50SZheng Yan fclose(file); 501a6146d50SZheng Yan } 502a6146d50SZheng Yan 503a6146d50SZheng Yan closedir(event_dir); 504940db6dcSAndi Kleen return 0; 505a6146d50SZheng Yan } 506a6146d50SZheng Yan 507a6146d50SZheng Yan /* 508a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 509a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 510a6146d50SZheng Yan */ 511e293a5e8SNamhyung Kim static int pmu_aliases(int dirfd, const char *name, struct list_head *head) 512a6146d50SZheng Yan { 513e293a5e8SNamhyung Kim int fd; 514a6146d50SZheng Yan 515e293a5e8SNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "events", O_DIRECTORY); 516e293a5e8SNamhyung Kim if (fd < 0) 517d9664582SAndi Kleen return 0; 518a6146d50SZheng Yan 519e293a5e8SNamhyung Kim /* it'll close the fd */ 520e293a5e8SNamhyung Kim if (pmu_aliases_parse(fd, head)) 521a6146d50SZheng Yan return -1; 522a6146d50SZheng Yan 523a6146d50SZheng Yan return 0; 524a6146d50SZheng Yan } 525a6146d50SZheng Yan 5265c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 527a6146d50SZheng Yan struct list_head *terms) 528a6146d50SZheng Yan { 5297c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 530a6146d50SZheng Yan LIST_HEAD(list); 531a6146d50SZheng Yan int ret; 532a6146d50SZheng Yan 533a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5347c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 535a6146d50SZheng Yan if (ret) { 536682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 537a6146d50SZheng Yan return ret; 538a6146d50SZheng Yan } 539c2f1ceadSAndi Kleen /* 540c2f1ceadSAndi Kleen * Weak terms don't override command line options, 541c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 542c2f1ceadSAndi Kleen */ 543c2f1ceadSAndi Kleen cloned->weak = true; 5447c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 545a6146d50SZheng Yan } 546a6146d50SZheng Yan list_splice(&list, terms); 547a6146d50SZheng Yan return 0; 548a6146d50SZheng Yan } 549a6146d50SZheng Yan 55066ec1191SMark Rutland /* 55166ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 55266ec1191SMark Rutland * may have a "cpus" file. 55366ec1191SMark Rutland */ 554*d06593aaSIan Rogers static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name, bool is_core) 5557ae92e74SYan, Zheng { 556f854839bSJiri Olsa struct perf_cpu_map *cpus; 5577e3fcffeSMark Rutland const char *templates[] = { 558d50a79cdSJames Clark "cpumask", 559d50a79cdSJames Clark "cpus", 5607e3fcffeSMark Rutland NULL 5617e3fcffeSMark Rutland }; 5627e3fcffeSMark Rutland const char **template; 563d50a79cdSJames Clark char pmu_name[PATH_MAX]; 564d50a79cdSJames Clark struct perf_pmu pmu = {.name = pmu_name}; 565d50a79cdSJames Clark FILE *file; 5667ae92e74SYan, Zheng 567d50a79cdSJames Clark strlcpy(pmu_name, name, sizeof(pmu_name)); 5687e3fcffeSMark Rutland for (template = templates; *template; template++) { 5693a69672eSNamhyung Kim file = perf_pmu__open_file_at(&pmu, dirfd, *template); 570d50a79cdSJames Clark if (!file) 571d50a79cdSJames Clark continue; 572d50a79cdSJames Clark cpus = perf_cpu_map__read(file); 5733a69672eSNamhyung Kim fclose(file); 57466ec1191SMark Rutland if (cpus) 57566ec1191SMark Rutland return cpus; 5767e3fcffeSMark Rutland } 5777ae92e74SYan, Zheng 578*d06593aaSIan Rogers /* Nothing found, for core PMUs assume this means all CPUs. */ 579*d06593aaSIan Rogers return is_core ? perf_cpu_map__get(cpu_map__online()) : NULL; 58066ec1191SMark Rutland } 5817ae92e74SYan, Zheng 5823a69672eSNamhyung Kim static bool pmu_is_uncore(int dirfd, const char *name) 58366ec1191SMark Rutland { 5843a69672eSNamhyung Kim int fd; 5857ae92e74SYan, Zheng 5863a69672eSNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "cpumask", O_PATH); 5873a69672eSNamhyung Kim if (fd < 0) 5883a69672eSNamhyung Kim return false; 5893a69672eSNamhyung Kim 5903a69672eSNamhyung Kim close(fd); 5913a69672eSNamhyung Kim return true; 5927ae92e74SYan, Zheng } 5937ae92e74SYan, Zheng 59451d54847SJohn Garry static char *pmu_id(const char *name) 59551d54847SJohn Garry { 59651d54847SJohn Garry char path[PATH_MAX], *str; 59751d54847SJohn Garry size_t len; 59851d54847SJohn Garry 5995f2c8efaSJames Clark perf_pmu__pathname_scnprintf(path, sizeof(path), name, "identifier"); 60051d54847SJohn Garry 6015f2c8efaSJames Clark if (filename__read_str(path, &str, &len) < 0) 60251d54847SJohn Garry return NULL; 60351d54847SJohn Garry 60451d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 60551d54847SJohn Garry 60651d54847SJohn Garry return str; 60751d54847SJohn Garry } 60851d54847SJohn Garry 6094bf7e81aSIan Rogers /** 6104bf7e81aSIan Rogers * is_sysfs_pmu_core() - PMU CORE devices have different name other than cpu in 6114bf7e81aSIan Rogers * sysfs on some platforms like ARM or Intel hybrid. Looking for 6124bf7e81aSIan Rogers * possible the cpus file in sysfs files to identify whether this is a 6134bf7e81aSIan Rogers * core device. 6144bf7e81aSIan Rogers * @name: The PMU name such as "cpu_atom". 61514b22ae0SGanapatrao Kulkarni */ 6164bf7e81aSIan Rogers static int is_sysfs_pmu_core(const char *name) 61714b22ae0SGanapatrao Kulkarni { 61814b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 61914b22ae0SGanapatrao Kulkarni 620f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpus")) 62114b22ae0SGanapatrao Kulkarni return 0; 622d9664582SAndi Kleen return file_available(path); 62314b22ae0SGanapatrao Kulkarni } 62414b22ae0SGanapatrao Kulkarni 62529be2fe0SIan Rogers char *perf_pmu__getcpuid(struct perf_pmu *pmu) 626d77ade9fSAndi Kleen { 627d77ade9fSAndi Kleen char *cpuid; 628d77ade9fSAndi Kleen static bool printed; 629d77ade9fSAndi Kleen 630d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 631d77ade9fSAndi Kleen if (cpuid) 632d77ade9fSAndi Kleen cpuid = strdup(cpuid); 633d77ade9fSAndi Kleen if (!cpuid) 63454e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 635d77ade9fSAndi Kleen if (!cpuid) 636d77ade9fSAndi Kleen return NULL; 637d77ade9fSAndi Kleen 638d77ade9fSAndi Kleen if (!printed) { 639d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 640d77ade9fSAndi Kleen printed = true; 641d77ade9fSAndi Kleen } 642d77ade9fSAndi Kleen return cpuid; 643d77ade9fSAndi Kleen } 644d77ade9fSAndi Kleen 6451ba3752aSIan Rogers __weak const struct pmu_events_table *pmu_events_table__find(void) 646e126bef5SJohn Garry { 64796d2a746SIan Rogers return perf_pmu__find_events_table(NULL); 648e126bef5SJohn Garry } 649e126bef5SJohn Garry 650f8ea2c15SIan Rogers __weak const struct pmu_metrics_table *pmu_metrics_table__find(void) 651f8ea2c15SIan Rogers { 652f8ea2c15SIan Rogers return perf_pmu__find_metrics_table(NULL); 653f8ea2c15SIan Rogers } 654f8ea2c15SIan Rogers 655240e6fd0SIan Rogers /** 656240e6fd0SIan Rogers * perf_pmu__match_ignoring_suffix - Does the pmu_name match tok ignoring any 657240e6fd0SIan Rogers * trailing suffix? The Suffix must be in form 658240e6fd0SIan Rogers * tok_{digits}, or tok{digits}. 659240e6fd0SIan Rogers * @pmu_name: The pmu_name with possible suffix. 660240e6fd0SIan Rogers * @tok: The possible match to pmu_name without suffix. 661c07d5c92SJohn Garry */ 662240e6fd0SIan Rogers static bool perf_pmu__match_ignoring_suffix(const char *pmu_name, const char *tok) 663c47a5599SJin Yao { 664c07d5c92SJohn Garry const char *p; 665c47a5599SJin Yao 666c47a5599SJin Yao if (strncmp(pmu_name, tok, strlen(tok))) 667c47a5599SJin Yao return false; 668c47a5599SJin Yao 669c47a5599SJin Yao p = pmu_name + strlen(tok); 670c47a5599SJin Yao if (*p == 0) 671c47a5599SJin Yao return true; 672c47a5599SJin Yao 673c07d5c92SJohn Garry if (*p == '_') 674c47a5599SJin Yao ++p; 675c07d5c92SJohn Garry 676c07d5c92SJohn Garry /* Ensure we end in a number */ 677c07d5c92SJohn Garry while (1) { 678c07d5c92SJohn Garry if (!isdigit(*p)) 679c47a5599SJin Yao return false; 680c07d5c92SJohn Garry if (*(++p) == 0) 681c07d5c92SJohn Garry break; 682c07d5c92SJohn Garry } 683c47a5599SJin Yao 684c47a5599SJin Yao return true; 685c47a5599SJin Yao } 686c47a5599SJin Yao 687240e6fd0SIan Rogers /** 688240e6fd0SIan Rogers * pmu_uncore_alias_match - does name match the PMU name? 689240e6fd0SIan Rogers * @pmu_name: the json struct pmu_event name. This may lack a suffix (which 690240e6fd0SIan Rogers * matches) or be of the form "socket,pmuname" which will match 691240e6fd0SIan Rogers * "socketX_pmunameY". 692240e6fd0SIan Rogers * @name: a real full PMU name as from sysfs. 693240e6fd0SIan Rogers */ 694240e6fd0SIan Rogers static bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 695730670b1SJohn Garry { 696730670b1SJohn Garry char *tmp = NULL, *tok, *str; 697730670b1SJohn Garry bool res; 698730670b1SJohn Garry 699240e6fd0SIan Rogers if (strchr(pmu_name, ',') == NULL) 700240e6fd0SIan Rogers return perf_pmu__match_ignoring_suffix(name, pmu_name); 701240e6fd0SIan Rogers 702730670b1SJohn Garry str = strdup(pmu_name); 703730670b1SJohn Garry if (!str) 704730670b1SJohn Garry return false; 705730670b1SJohn Garry 706730670b1SJohn Garry /* 707730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 708730670b1SJohn Garry */ 709730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 710730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 711730670b1SJohn Garry res = false; 712730670b1SJohn Garry goto out; 713730670b1SJohn Garry } 714730670b1SJohn Garry 715730670b1SJohn Garry /* 716730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 717730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 718730670b1SJohn Garry * 719730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 720730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 721730670b1SJohn Garry * "pmunameY". 722730670b1SJohn Garry */ 723c07d5c92SJohn Garry while (1) { 724c07d5c92SJohn Garry char *next_tok = strtok_r(NULL, ",", &tmp); 725c07d5c92SJohn Garry 726730670b1SJohn Garry name = strstr(name, tok); 727c07d5c92SJohn Garry if (!name || 728240e6fd0SIan Rogers (!next_tok && !perf_pmu__match_ignoring_suffix(name, tok))) { 729730670b1SJohn Garry res = false; 730730670b1SJohn Garry goto out; 731730670b1SJohn Garry } 732c07d5c92SJohn Garry if (!next_tok) 733c07d5c92SJohn Garry break; 734c07d5c92SJohn Garry tok = next_tok; 735c07d5c92SJohn Garry name += strlen(tok); 736730670b1SJohn Garry } 737730670b1SJohn Garry 738730670b1SJohn Garry res = true; 739730670b1SJohn Garry out: 740730670b1SJohn Garry free(str); 741730670b1SJohn Garry return res; 742730670b1SJohn Garry } 743730670b1SJohn Garry 744660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data { 745d685819bSIan Rogers /* List being added to. */ 746660842e4SIan Rogers struct list_head *head; 747d685819bSIan Rogers /* If a pmu_event lacks a given PMU the default used. */ 748d685819bSIan Rogers char *default_pmu_name; 749d685819bSIan Rogers /* The PMU that we're searching for events for. */ 750660842e4SIan Rogers struct perf_pmu *pmu; 751660842e4SIan Rogers }; 752660842e4SIan Rogers 753660842e4SIan Rogers static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, 7541ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 755660842e4SIan Rogers void *vdata) 756660842e4SIan Rogers { 757660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data *data = vdata; 758d685819bSIan Rogers const char *pname = pe->pmu ?: data->default_pmu_name; 759660842e4SIan Rogers 760d685819bSIan Rogers if (!strcmp(pname, data->pmu->name) || 761d685819bSIan Rogers (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->pmu->name))) { 762660842e4SIan Rogers /* need type casts to override 'const' */ 763e293a5e8SNamhyung Kim __perf_pmu__new_alias(data->head, -1, (char *)pe->name, (char *)pe->desc, 764660842e4SIan Rogers (char *)pe->event, pe); 765d685819bSIan Rogers } 766660842e4SIan Rogers return 0; 767660842e4SIan Rogers } 768660842e4SIan Rogers 769933f82ffSSukadev Bhattiprolu /* 770d685819bSIan Rogers * From the pmu_events_table, find the events that correspond to the given 771d685819bSIan Rogers * PMU and add them to the list 'head'. 772933f82ffSSukadev Bhattiprolu */ 773eeac7730SIan Rogers void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu, 7741ba3752aSIan Rogers const struct pmu_events_table *table) 775933f82ffSSukadev Bhattiprolu { 776660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data data = { 777660842e4SIan Rogers .head = head, 778d685819bSIan Rogers .default_pmu_name = perf_pmus__default_pmu_name(), 779660842e4SIan Rogers .pmu = pmu, 780660842e4SIan Rogers }; 781fedb2b51SAndi Kleen 782660842e4SIan Rogers pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data); 783d685819bSIan Rogers free(data.default_pmu_name); 784933f82ffSSukadev Bhattiprolu } 785933f82ffSSukadev Bhattiprolu 786e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 787e45ad701SJohn Garry { 7881ba3752aSIan Rogers const struct pmu_events_table *table; 789e45ad701SJohn Garry 79096d2a746SIan Rogers table = perf_pmu__find_events_table(pmu); 791eeac7730SIan Rogers if (!table) 792e45ad701SJohn Garry return; 793e45ad701SJohn Garry 794eeac7730SIan Rogers pmu_add_cpu_aliases_table(head, pmu, table); 795e45ad701SJohn Garry } 796e45ad701SJohn Garry 7974513c719SJohn Garry struct pmu_sys_event_iter_data { 7984513c719SJohn Garry struct list_head *head; 7994513c719SJohn Garry struct perf_pmu *pmu; 8004513c719SJohn Garry }; 8014513c719SJohn Garry 80229be2fe0SIan Rogers static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, 8031ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 80429be2fe0SIan Rogers void *data) 8054513c719SJohn Garry { 8064513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8074513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8084513c719SJohn Garry 8094513c719SJohn Garry if (!pe->compat || !pe->pmu) 8104513c719SJohn Garry return 0; 8114513c719SJohn Garry 8124513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8134513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 814e293a5e8SNamhyung Kim __perf_pmu__new_alias(idata->head, -1, 8154513c719SJohn Garry (char *)pe->name, 8164513c719SJohn Garry (char *)pe->desc, 8174513c719SJohn Garry (char *)pe->event, 818eab35953SJin Yao pe); 8194513c719SJohn Garry } 8204513c719SJohn Garry 8214513c719SJohn Garry return 0; 8224513c719SJohn Garry } 8234513c719SJohn Garry 824e199f47fSJohn Garry void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 8254513c719SJohn Garry { 8264513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 8274513c719SJohn Garry .head = head, 8284513c719SJohn Garry .pmu = pmu, 8294513c719SJohn Garry }; 8304513c719SJohn Garry 8314513c719SJohn Garry if (!pmu->id) 8324513c719SJohn Garry return; 8334513c719SJohn Garry 8344513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 8354513c719SJohn Garry } 8364513c719SJohn Garry 837c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 838dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 839dc0a6202SAdrian Hunter { 840dc0a6202SAdrian Hunter return NULL; 841dc0a6202SAdrian Hunter } 842dc0a6202SAdrian Hunter 84313d60ba0SKan Liang char * __weak 84413d60ba0SKan Liang pmu_find_real_name(const char *name) 84513d60ba0SKan Liang { 84613d60ba0SKan Liang return (char *)name; 84713d60ba0SKan Liang } 84813d60ba0SKan Liang 84913d60ba0SKan Liang char * __weak 85013d60ba0SKan Liang pmu_find_alias_name(const char *name __maybe_unused) 85113d60ba0SKan Liang { 85213d60ba0SKan Liang return NULL; 85313d60ba0SKan Liang } 85413d60ba0SKan Liang 8553a69672eSNamhyung Kim static int pmu_max_precise(int dirfd, struct perf_pmu *pmu) 85690a86bdeSJiri Olsa { 85790a86bdeSJiri Olsa int max_precise = -1; 85890a86bdeSJiri Olsa 8593a69672eSNamhyung Kim perf_pmu__scan_file_at(pmu, dirfd, "caps/max_precise", "%d", &max_precise); 86090a86bdeSJiri Olsa return max_precise; 86190a86bdeSJiri Olsa } 86290a86bdeSJiri Olsa 8631eaf496eSIan Rogers struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name) 864cd82a32eSJiri Olsa { 865cd82a32eSJiri Olsa struct perf_pmu *pmu; 866cd82a32eSJiri Olsa LIST_HEAD(format); 867a6146d50SZheng Yan LIST_HEAD(aliases); 868cd82a32eSJiri Olsa __u32 type; 86913d60ba0SKan Liang char *name = pmu_find_real_name(lookup_name); 87013d60ba0SKan Liang char *alias_name; 87149afa7f6SJin Yao 87249afa7f6SJin Yao /* 873cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 874cd82a32eSJiri Olsa * type value and format definitions. Load both right 875cd82a32eSJiri Olsa * now. 876cd82a32eSJiri Olsa */ 877e293a5e8SNamhyung Kim if (pmu_format(dirfd, name, &format)) 878cd82a32eSJiri Olsa return NULL; 879cd82a32eSJiri Olsa 88015b22ed3SAndi Kleen /* 881f8ad6018SJames Clark * Check the aliases first to avoid unnecessary work. 88215b22ed3SAndi Kleen */ 883e293a5e8SNamhyung Kim if (pmu_aliases(dirfd, name, &aliases)) 8843fded963SJiri Olsa return NULL; 8853fded963SJiri Olsa 886cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 887cd82a32eSJiri Olsa if (!pmu) 888cd82a32eSJiri Olsa return NULL; 889cd82a32eSJiri Olsa 890*d06593aaSIan Rogers pmu->is_core = is_pmu_core(name); 891*d06593aaSIan Rogers pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core); 89254e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 89313d60ba0SKan Liang if (!pmu->name) 89413d60ba0SKan Liang goto err; 89513d60ba0SKan Liang 896f8ad6018SJames Clark /* Read type, and ensure that type value is successfully assigned (return 1) */ 8973a69672eSNamhyung Kim if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &type) != 1) 898f8ad6018SJames Clark goto err; 899f8ad6018SJames Clark 90013d60ba0SKan Liang alias_name = pmu_find_alias_name(name); 90113d60ba0SKan Liang if (alias_name) { 90213d60ba0SKan Liang pmu->alias_name = strdup(alias_name); 90313d60ba0SKan Liang if (!pmu->alias_name) 90413d60ba0SKan Liang goto err; 90513d60ba0SKan Liang } 90613d60ba0SKan Liang 90754e32dc0SGanapatrao Kulkarni pmu->type = type; 9083a69672eSNamhyung Kim pmu->is_uncore = pmu_is_uncore(dirfd, name); 90951d54847SJohn Garry if (pmu->is_uncore) 91051d54847SJohn Garry pmu->id = pmu_id(name); 9113a69672eSNamhyung Kim pmu->max_precise = pmu_max_precise(dirfd, pmu); 91254e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 9134513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 91466ec1191SMark Rutland 915cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 916a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 9179fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 918cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 919a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 9201eaf496eSIan Rogers list_add_tail(&pmu->list, pmus); 921dc0a6202SAdrian Hunter 922dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 923dc0a6202SAdrian Hunter 924cd82a32eSJiri Olsa return pmu; 92513d60ba0SKan Liang err: 926efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->name); 92713d60ba0SKan Liang free(pmu); 92813d60ba0SKan Liang return NULL; 929cd82a32eSJiri Olsa } 930cd82a32eSJiri Olsa 931e552b7beSRob Herring void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) 932e552b7beSRob Herring { 933e552b7beSRob Herring struct perf_pmu_format *format; 934e552b7beSRob Herring 93568c25043SIan Rogers if (pmu->formats_checked) 93668c25043SIan Rogers return; 93768c25043SIan Rogers 93868c25043SIan Rogers pmu->formats_checked = true; 93968c25043SIan Rogers 940e552b7beSRob Herring /* fake pmu doesn't have format list */ 941e552b7beSRob Herring if (pmu == &perf_pmu__fake) 942e552b7beSRob Herring return; 943e552b7beSRob Herring 944e552b7beSRob Herring list_for_each_entry(format, &pmu->format, list) 945e552b7beSRob Herring if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) { 946e552b7beSRob Herring pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'" 947e552b7beSRob Herring "which is not supported by this version of perf!\n", 948e552b7beSRob Herring pmu->name, format->name, format->value); 949e552b7beSRob Herring return; 950e552b7beSRob Herring } 951e552b7beSRob Herring } 952e552b7beSRob Herring 953c6d616feSIan Rogers bool evsel__is_aux_event(const struct evsel *evsel) 954e12ee9f7SAdrian Hunter { 955e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 956e12ee9f7SAdrian Hunter 957e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 958e12ee9f7SAdrian Hunter } 959e12ee9f7SAdrian Hunter 9606593f019SJames Clark /* 9616593f019SJames Clark * Set @config_name to @val as long as the user hasn't already set or cleared it 9626593f019SJames Clark * by passing a config term on the command line. 9636593f019SJames Clark * 9646593f019SJames Clark * @val is the value to put into the bits specified by @config_name rather than 9656593f019SJames Clark * the bit pattern. It is shifted into position by this function, so to set 9666593f019SJames Clark * something to true, pass 1 for val rather than a pre shifted value. 9676593f019SJames Clark */ 9686593f019SJames Clark #define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask)) 9696593f019SJames Clark void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel, 9706593f019SJames Clark const char *config_name, u64 val) 9716593f019SJames Clark { 9726593f019SJames Clark u64 user_bits = 0, bits; 9736593f019SJames Clark struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG); 9746593f019SJames Clark 9756593f019SJames Clark if (term) 9766593f019SJames Clark user_bits = term->val.cfg_chg; 9776593f019SJames Clark 9786593f019SJames Clark bits = perf_pmu__format_bits(&pmu->format, config_name); 9796593f019SJames Clark 9806593f019SJames Clark /* Do nothing if the user changed the value */ 9816593f019SJames Clark if (bits & user_bits) 9826593f019SJames Clark return; 9836593f019SJames Clark 9846593f019SJames Clark /* Otherwise replace it */ 9856593f019SJames Clark evsel->core.attr.config &= ~bits; 9866593f019SJames Clark evsel->core.attr.config |= field_prep(bits, val); 9876593f019SJames Clark } 9886593f019SJames Clark 9895c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 99009ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 991cd82a32eSJiri Olsa { 9925c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 993cd82a32eSJiri Olsa 994cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 995cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 996cd82a32eSJiri Olsa return format; 997cd82a32eSJiri Olsa 998cd82a32eSJiri Olsa return NULL; 999cd82a32eSJiri Olsa } 1000cd82a32eSJiri Olsa 100109ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 100209ff6071SAdrian Hunter { 100309ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 100409ff6071SAdrian Hunter __u64 bits = 0; 100509ff6071SAdrian Hunter int fbit; 100609ff6071SAdrian Hunter 100709ff6071SAdrian Hunter if (!format) 100809ff6071SAdrian Hunter return 0; 100909ff6071SAdrian Hunter 101009ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 101109ff6071SAdrian Hunter bits |= 1ULL << fbit; 101209ff6071SAdrian Hunter 101309ff6071SAdrian Hunter return bits; 101409ff6071SAdrian Hunter } 101509ff6071SAdrian Hunter 1016a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1017a1ac7de6SAdrian Hunter { 1018a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1019a1ac7de6SAdrian Hunter 1020a1ac7de6SAdrian Hunter if (!format) 1021a1ac7de6SAdrian Hunter return -1; 1022a1ac7de6SAdrian Hunter 1023a1ac7de6SAdrian Hunter return format->value; 1024a1ac7de6SAdrian Hunter } 1025a1ac7de6SAdrian Hunter 1026cd82a32eSJiri Olsa /* 1027dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 10284d39c89fSIngo Molnar * and unformatted value (value parameter). 1029cd82a32eSJiri Olsa */ 1030dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1031dc0a6202SAdrian Hunter bool zero) 1032cd82a32eSJiri Olsa { 1033cd82a32eSJiri Olsa unsigned long fbit, vbit; 1034cd82a32eSJiri Olsa 1035cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1036cd82a32eSJiri Olsa 1037cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1038cd82a32eSJiri Olsa continue; 1039cd82a32eSJiri Olsa 1040dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1041dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1042dc0a6202SAdrian Hunter else if (zero) 1043dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1044cd82a32eSJiri Olsa } 1045cd82a32eSJiri Olsa } 1046cd82a32eSJiri Olsa 10470efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 10480efe6b67SAdrian Hunter { 10491b9caa10SJiri Olsa int w; 10500efe6b67SAdrian Hunter 10511b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 10521b9caa10SJiri Olsa if (!w) 10531b9caa10SJiri Olsa return 0; 10541b9caa10SJiri Olsa if (w < 64) 10551b9caa10SJiri Olsa return (1ULL << w) - 1; 10561b9caa10SJiri Olsa return -1; 10570efe6b67SAdrian Hunter } 10580efe6b67SAdrian Hunter 1059cd82a32eSJiri Olsa /* 1060688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1061688d4dfcSCody P Schafer * in the remaining terms. 1062688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1063688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1064688d4dfcSCody P Schafer * in a config string) later on in the term list. 1065688d4dfcSCody P Schafer */ 1066688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1067688d4dfcSCody P Schafer struct list_head *head_terms, 1068688d4dfcSCody P Schafer __u64 *value) 1069688d4dfcSCody P Schafer { 1070688d4dfcSCody P Schafer struct parse_events_term *t; 1071688d4dfcSCody P Schafer 1072688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 10732a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 10742a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1075688d4dfcSCody P Schafer t->used = true; 1076688d4dfcSCody P Schafer *value = t->val.num; 1077688d4dfcSCody P Schafer return 0; 1078688d4dfcSCody P Schafer } 1079688d4dfcSCody P Schafer } 1080688d4dfcSCody P Schafer 1081bb963e16SNamhyung Kim if (verbose > 0) 1082688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1083688d4dfcSCody P Schafer 1084688d4dfcSCody P Schafer return -1; 1085688d4dfcSCody P Schafer } 1086688d4dfcSCody P Schafer 1087ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1088e64b020bSJiri Olsa { 1089e64b020bSJiri Olsa struct perf_pmu_format *format; 109011db4e29SMasami Hiramatsu char *str = NULL; 109111db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1092f1417ceaSXin Gao unsigned int i = 0; 1093e64b020bSJiri Olsa 1094ffeb883eSHe Kuang if (!formats) 1095e64b020bSJiri Olsa return NULL; 1096e64b020bSJiri Olsa 1097e64b020bSJiri Olsa /* sysfs exported terms */ 1098ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 109911db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 110011db4e29SMasami Hiramatsu goto error; 1101e64b020bSJiri Olsa 1102ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 110311db4e29SMasami Hiramatsu error: 1104ffeb883eSHe Kuang strbuf_release(&buf); 1105e64b020bSJiri Olsa 1106e64b020bSJiri Olsa return str; 1107e64b020bSJiri Olsa } 1108e64b020bSJiri Olsa 1109688d4dfcSCody P Schafer /* 1110cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 111188aca8d9SCody P Schafer * user input data - term parameter. 1112cd82a32eSJiri Olsa */ 11134ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 11144ac22b48SIan Rogers struct list_head *formats, 1115cd82a32eSJiri Olsa struct perf_event_attr *attr, 1116dc0a6202SAdrian Hunter struct parse_events_term *term, 1117688d4dfcSCody P Schafer struct list_head *head_terms, 1118e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1119cd82a32eSJiri Olsa { 11205c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1121cd82a32eSJiri Olsa __u64 *vp; 11220efe6b67SAdrian Hunter __u64 val, max_val; 1123cd82a32eSJiri Olsa 1124cd82a32eSJiri Olsa /* 1125688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1126688d4dfcSCody P Schafer * skip it in normal eval. 1127688d4dfcSCody P Schafer */ 1128688d4dfcSCody P Schafer if (term->used) 1129688d4dfcSCody P Schafer return 0; 1130688d4dfcSCody P Schafer 1131688d4dfcSCody P Schafer /* 1132cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1133cd82a32eSJiri Olsa * to be done for them. 1134cd82a32eSJiri Olsa */ 1135cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1136cd82a32eSJiri Olsa return 0; 1137cd82a32eSJiri Olsa 1138cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1139688d4dfcSCody P Schafer if (!format) { 1140ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 11414ac22b48SIan Rogers char *unknown_term; 11424ac22b48SIan Rogers char *help_msg; 1143ffeb883eSHe Kuang 11444ac22b48SIan Rogers if (asprintf(&unknown_term, 11454ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 11464ac22b48SIan Rogers term->config, pmu_name) < 0) 11474ac22b48SIan Rogers unknown_term = NULL; 11484ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 11494ac22b48SIan Rogers if (err) { 11506c191289SIan Rogers parse_events_error__handle(err, term->err_term, 11514ac22b48SIan Rogers unknown_term, 11524ac22b48SIan Rogers help_msg); 11534ac22b48SIan Rogers } else { 11544ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 11554ac22b48SIan Rogers free(unknown_term); 1156e64b020bSJiri Olsa } 11574ac22b48SIan Rogers free(pmu_term); 1158cd82a32eSJiri Olsa return -EINVAL; 1159688d4dfcSCody P Schafer } 1160cd82a32eSJiri Olsa 1161cd82a32eSJiri Olsa switch (format->value) { 1162cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1163cd82a32eSJiri Olsa vp = &attr->config; 1164cd82a32eSJiri Olsa break; 1165cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1166cd82a32eSJiri Olsa vp = &attr->config1; 1167cd82a32eSJiri Olsa break; 1168cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1169cd82a32eSJiri Olsa vp = &attr->config2; 1170cd82a32eSJiri Olsa break; 1171204e7c49SRob Herring case PERF_PMU_FORMAT_VALUE_CONFIG3: 1172204e7c49SRob Herring vp = &attr->config3; 1173204e7c49SRob Herring break; 1174cd82a32eSJiri Olsa default: 1175cd82a32eSJiri Olsa return -EINVAL; 1176cd82a32eSJiri Olsa } 1177cd82a32eSJiri Olsa 117816fa7e82SJiri Olsa /* 1179688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1180688d4dfcSCody P Schafer * using event parameters. 118116fa7e82SJiri Olsa */ 118299e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 118399e7138eSJiri Olsa if (term->no_value && 118499e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 118599e7138eSJiri Olsa if (err) { 11866c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1187448d732cSIan Rogers strdup("no value assigned for term"), 1188448d732cSIan Rogers NULL); 118999e7138eSJiri Olsa } 119099e7138eSJiri Olsa return -EINVAL; 119199e7138eSJiri Olsa } 119299e7138eSJiri Olsa 1193688d4dfcSCody P Schafer val = term->val.num; 119499e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1195688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1196bb963e16SNamhyung Kim if (verbose > 0) { 1197688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1198688d4dfcSCody P Schafer term->config, term->val.str); 1199e64b020bSJiri Olsa } 1200e64b020bSJiri Olsa if (err) { 12016c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1202448d732cSIan Rogers strdup("expected numeric value"), 1203448d732cSIan Rogers NULL); 1204e64b020bSJiri Olsa } 1205688d4dfcSCody P Schafer return -EINVAL; 1206688d4dfcSCody P Schafer } 1207688d4dfcSCody P Schafer 1208688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1209688d4dfcSCody P Schafer return -EINVAL; 1210688d4dfcSCody P Schafer } else 1211688d4dfcSCody P Schafer return -EINVAL; 1212688d4dfcSCody P Schafer 12130efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 12140efe6b67SAdrian Hunter if (val > max_val) { 12150efe6b67SAdrian Hunter if (err) { 1216448d732cSIan Rogers char *err_str; 1217448d732cSIan Rogers 12186c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1219448d732cSIan Rogers asprintf(&err_str, 12200efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1221448d732cSIan Rogers (unsigned long long)max_val) < 0 1222448d732cSIan Rogers ? strdup("value too big for format") 1223448d732cSIan Rogers : err_str, 1224448d732cSIan Rogers NULL); 12250efe6b67SAdrian Hunter return -EINVAL; 12260efe6b67SAdrian Hunter } 12270efe6b67SAdrian Hunter /* 12280efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 12290efe6b67SAdrian Hunter * silently truncated. 12300efe6b67SAdrian Hunter */ 12310efe6b67SAdrian Hunter } 12320efe6b67SAdrian Hunter 1233688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1234cd82a32eSJiri Olsa return 0; 1235cd82a32eSJiri Olsa } 1236cd82a32eSJiri Olsa 12374ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1238cff7f956SJiri Olsa struct perf_event_attr *attr, 1239dc0a6202SAdrian Hunter struct list_head *head_terms, 1240e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1241cd82a32eSJiri Olsa { 12426cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1243cd82a32eSJiri Olsa 1244688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 12454ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1246e64b020bSJiri Olsa zero, err)) 1247cd82a32eSJiri Olsa return -EINVAL; 1248688d4dfcSCody P Schafer } 1249cd82a32eSJiri Olsa 1250cd82a32eSJiri Olsa return 0; 1251cd82a32eSJiri Olsa } 1252cd82a32eSJiri Olsa 1253cd82a32eSJiri Olsa /* 1254cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1255cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1256cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1257cd82a32eSJiri Olsa */ 1258cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1259e64b020bSJiri Olsa struct list_head *head_terms, 1260e64b020bSJiri Olsa struct parse_events_error *err) 1261cd82a32eSJiri Olsa { 1262dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1263dc0a6202SAdrian Hunter 12644ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 12654ac22b48SIan Rogers head_terms, zero, err); 1266cd82a32eSJiri Olsa } 1267cd82a32eSJiri Olsa 12685c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 12696cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1270a6146d50SZheng Yan { 12715c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1272a6146d50SZheng Yan char *name; 1273a6146d50SZheng Yan 1274a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1275a6146d50SZheng Yan return NULL; 1276a6146d50SZheng Yan 1277a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1278a6146d50SZheng Yan if (term->val.num != 1) 1279a6146d50SZheng Yan return NULL; 1280a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1281a6146d50SZheng Yan return NULL; 1282a6146d50SZheng Yan name = term->config; 1283a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1284a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1285a6146d50SZheng Yan return NULL; 1286a6146d50SZheng Yan name = term->val.str; 1287a6146d50SZheng Yan } else { 1288a6146d50SZheng Yan return NULL; 1289a6146d50SZheng Yan } 1290a6146d50SZheng Yan 1291a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1292a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1293a6146d50SZheng Yan return alias; 1294a6146d50SZheng Yan } 1295a6146d50SZheng Yan return NULL; 1296a6146d50SZheng Yan } 1297a6146d50SZheng Yan 1298410136f5SStephane Eranian 12991d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 13001d9e446bSJiri Olsa struct perf_pmu_info *info) 1301410136f5SStephane Eranian { 1302410136f5SStephane Eranian /* 1303410136f5SStephane Eranian * Only one term in event definition can 13041d9e446bSJiri Olsa * define unit, scale and snapshot, fail 13051d9e446bSJiri Olsa * if there's more than one. 1306410136f5SStephane Eranian */ 1307b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 13081d9e446bSJiri Olsa (info->scale && alias->scale) || 13091d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1310410136f5SStephane Eranian return -EINVAL; 1311410136f5SStephane Eranian 1312b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 13131d9e446bSJiri Olsa info->unit = alias->unit; 1314410136f5SStephane Eranian 1315410136f5SStephane Eranian if (alias->scale) 13161d9e446bSJiri Olsa info->scale = alias->scale; 13171d9e446bSJiri Olsa 13181d9e446bSJiri Olsa if (alias->snapshot) 13191d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1320410136f5SStephane Eranian 1321410136f5SStephane Eranian return 0; 1322410136f5SStephane Eranian } 1323410136f5SStephane Eranian 1324a6146d50SZheng Yan /* 1325a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1326a6146d50SZheng Yan * defined for the alias 1327a6146d50SZheng Yan */ 1328410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 132946441bdcSMatt Fleming struct perf_pmu_info *info) 1330a6146d50SZheng Yan { 13316cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 13325c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1333a6146d50SZheng Yan int ret; 1334a6146d50SZheng Yan 1335044330c1SMatt Fleming info->per_pkg = false; 1336044330c1SMatt Fleming 13378a398897SStephane Eranian /* 13388a398897SStephane Eranian * Mark unit and scale as not set 13398a398897SStephane Eranian * (different from default values, see below) 13408a398897SStephane Eranian */ 134146441bdcSMatt Fleming info->unit = NULL; 134246441bdcSMatt Fleming info->scale = 0.0; 13431d9e446bSJiri Olsa info->snapshot = false; 1344410136f5SStephane Eranian 1345a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1346a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1347a6146d50SZheng Yan if (!alias) 1348a6146d50SZheng Yan continue; 1349a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1350a6146d50SZheng Yan if (ret) 1351a6146d50SZheng Yan return ret; 1352410136f5SStephane Eranian 13531d9e446bSJiri Olsa ret = check_info_data(alias, info); 1354410136f5SStephane Eranian if (ret) 1355410136f5SStephane Eranian return ret; 1356410136f5SStephane Eranian 1357044330c1SMatt Fleming if (alias->per_pkg) 1358044330c1SMatt Fleming info->per_pkg = true; 1359044330c1SMatt Fleming 1360e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 13611dc92556SIan Rogers parse_events_term__delete(term); 1362a6146d50SZheng Yan } 13638a398897SStephane Eranian 13648a398897SStephane Eranian /* 13658a398897SStephane Eranian * if no unit or scale found in aliases, then 13668a398897SStephane Eranian * set defaults as for evsel 13678a398897SStephane Eranian * unit cannot left to NULL 13688a398897SStephane Eranian */ 136946441bdcSMatt Fleming if (info->unit == NULL) 137046441bdcSMatt Fleming info->unit = ""; 13718a398897SStephane Eranian 137246441bdcSMatt Fleming if (info->scale == 0.0) 137346441bdcSMatt Fleming info->scale = 1.0; 13748a398897SStephane Eranian 1375a6146d50SZheng Yan return 0; 1376a6146d50SZheng Yan } 1377a6146d50SZheng Yan 1378cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1379cd82a32eSJiri Olsa int config, unsigned long *bits) 1380cd82a32eSJiri Olsa { 13815c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1382cd82a32eSJiri Olsa 1383cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1384cd82a32eSJiri Olsa if (!format) 1385cd82a32eSJiri Olsa return -ENOMEM; 1386cd82a32eSJiri Olsa 1387cd82a32eSJiri Olsa format->name = strdup(name); 1388cd82a32eSJiri Olsa format->value = config; 1389cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1390cd82a32eSJiri Olsa 1391cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1392cd82a32eSJiri Olsa return 0; 1393cd82a32eSJiri Olsa } 1394cd82a32eSJiri Olsa 1395cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1396cd82a32eSJiri Olsa { 1397cd82a32eSJiri Olsa long b; 1398cd82a32eSJiri Olsa 1399cd82a32eSJiri Olsa if (!to) 1400cd82a32eSJiri Olsa to = from; 1401cd82a32eSJiri Olsa 140215268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1403cd82a32eSJiri Olsa for (b = from; b <= to; b++) 140449bd97c2SSean Christopherson __set_bit(b, bits); 1405cd82a32eSJiri Olsa } 1406dc098b35SAndi Kleen 1407d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1408d26383dcSNamhyung Kim { 1409d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1410d26383dcSNamhyung Kim 1411d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1412d26383dcSNamhyung Kim list_del(&fmt->list); 1413efe98a7aSArnaldo Carvalho de Melo zfree(&fmt->name); 1414d26383dcSNamhyung Kim free(fmt); 1415d26383dcSNamhyung Kim } 1416d26383dcSNamhyung Kim } 1417d26383dcSNamhyung Kim 1418d504fae9SJohn Garry bool is_pmu_core(const char *name) 1419d504fae9SJohn Garry { 14206fbd67b0SThomas Richter return !strcmp(name, "cpu") || !strcmp(name, "cpum_cf") || is_sysfs_pmu_core(name); 14214bf7e81aSIan Rogers } 14224bf7e81aSIan Rogers 14236fd1e519SIan Rogers bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu) 14246fd1e519SIan Rogers { 1425e20d1f2fSIan Rogers return pmu->is_core; 14266fd1e519SIan Rogers } 14276fd1e519SIan Rogers 142852c7b4d3SIan Rogers bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu) 142952c7b4d3SIan Rogers { 1430e2342142SIan Rogers return pmu->is_core && perf_pmus__num_core_pmus() == 1; 143152c7b4d3SIan Rogers } 143252c7b4d3SIan Rogers 14331eaf496eSIan Rogers bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name) 1434abe9544eSIan Rogers { 14354cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 14364cabc3d1SAndi Kleen 14371eaf496eSIan Rogers list_for_each_entry(alias, &pmu->aliases, list) { 14384cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 14394cabc3d1SAndi Kleen return true; 14404cabc3d1SAndi Kleen } 14414cabc3d1SAndi Kleen return false; 14424cabc3d1SAndi Kleen } 14437d4bdab5SAdrian Hunter 1444251aa040SIan Rogers bool perf_pmu__is_software(const struct perf_pmu *pmu) 1445251aa040SIan Rogers { 1446251aa040SIan Rogers if (pmu->is_core || pmu->is_uncore || pmu->auxtrace) 1447251aa040SIan Rogers return false; 1448251aa040SIan Rogers switch (pmu->type) { 1449251aa040SIan Rogers case PERF_TYPE_HARDWARE: return false; 1450251aa040SIan Rogers case PERF_TYPE_SOFTWARE: return true; 1451251aa040SIan Rogers case PERF_TYPE_TRACEPOINT: return true; 1452251aa040SIan Rogers case PERF_TYPE_HW_CACHE: return false; 1453251aa040SIan Rogers case PERF_TYPE_RAW: return false; 1454251aa040SIan Rogers case PERF_TYPE_BREAKPOINT: return true; 1455251aa040SIan Rogers default: break; 1456251aa040SIan Rogers } 1457251aa040SIan Rogers return !strcmp(pmu->name, "kprobe") || !strcmp(pmu->name, "uprobe"); 1458251aa040SIan Rogers } 1459251aa040SIan Rogers 1460d50a79cdSJames Clark FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 14617d4bdab5SAdrian Hunter { 14627d4bdab5SAdrian Hunter char path[PATH_MAX]; 14637d4bdab5SAdrian Hunter 1464f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name) || 1465f8ad6018SJames Clark !file_available(path)) 14667d4bdab5SAdrian Hunter return NULL; 14677d4bdab5SAdrian Hunter 14687d4bdab5SAdrian Hunter return fopen(path, "r"); 14697d4bdab5SAdrian Hunter } 14707d4bdab5SAdrian Hunter 14713a69672eSNamhyung Kim FILE *perf_pmu__open_file_at(struct perf_pmu *pmu, int dirfd, const char *name) 14723a69672eSNamhyung Kim { 14733a69672eSNamhyung Kim int fd; 14743a69672eSNamhyung Kim 14753a69672eSNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, pmu->name, name, O_RDONLY); 14763a69672eSNamhyung Kim if (fd < 0) 14773a69672eSNamhyung Kim return NULL; 14783a69672eSNamhyung Kim 14793a69672eSNamhyung Kim return fdopen(fd, "r"); 14803a69672eSNamhyung Kim } 14813a69672eSNamhyung Kim 14827d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 14837d4bdab5SAdrian Hunter ...) 14847d4bdab5SAdrian Hunter { 14857d4bdab5SAdrian Hunter va_list args; 14867d4bdab5SAdrian Hunter FILE *file; 14877d4bdab5SAdrian Hunter int ret = EOF; 14887d4bdab5SAdrian Hunter 14897d4bdab5SAdrian Hunter va_start(args, fmt); 14907d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 14917d4bdab5SAdrian Hunter if (file) { 14927d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 14937d4bdab5SAdrian Hunter fclose(file); 14947d4bdab5SAdrian Hunter } 14957d4bdab5SAdrian Hunter va_end(args); 14967d4bdab5SAdrian Hunter return ret; 14977d4bdab5SAdrian Hunter } 14989fbc61f8SKan Liang 14993a69672eSNamhyung Kim int perf_pmu__scan_file_at(struct perf_pmu *pmu, int dirfd, const char *name, 15003a69672eSNamhyung Kim const char *fmt, ...) 15013a69672eSNamhyung Kim { 15023a69672eSNamhyung Kim va_list args; 15033a69672eSNamhyung Kim FILE *file; 15043a69672eSNamhyung Kim int ret = EOF; 15053a69672eSNamhyung Kim 15063a69672eSNamhyung Kim va_start(args, fmt); 15073a69672eSNamhyung Kim file = perf_pmu__open_file_at(pmu, dirfd, name); 15083a69672eSNamhyung Kim if (file) { 15093a69672eSNamhyung Kim ret = vfscanf(file, fmt, args); 15103a69672eSNamhyung Kim fclose(file); 15113a69672eSNamhyung Kim } 15123a69672eSNamhyung Kim va_end(args); 15133a69672eSNamhyung Kim return ret; 15143a69672eSNamhyung Kim } 15153a69672eSNamhyung Kim 1516c2b6a896SGerman Gomez bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name) 1517c2b6a896SGerman Gomez { 1518c2b6a896SGerman Gomez char path[PATH_MAX]; 1519c2b6a896SGerman Gomez 1520c2b6a896SGerman Gomez if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name)) 1521c2b6a896SGerman Gomez return false; 1522c2b6a896SGerman Gomez 1523c2b6a896SGerman Gomez return file_available(path); 1524c2b6a896SGerman Gomez } 1525c2b6a896SGerman Gomez 15269fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 15279fbc61f8SKan Liang { 15289fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 15299fbc61f8SKan Liang 15309fbc61f8SKan Liang if (!caps) 15319fbc61f8SKan Liang return -ENOMEM; 15329fbc61f8SKan Liang 15339fbc61f8SKan Liang caps->name = strdup(name); 15349fbc61f8SKan Liang if (!caps->name) 15359fbc61f8SKan Liang goto free_caps; 15369fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 15379fbc61f8SKan Liang if (!caps->value) 15389fbc61f8SKan Liang goto free_name; 15399fbc61f8SKan Liang list_add_tail(&caps->list, list); 15409fbc61f8SKan Liang return 0; 15419fbc61f8SKan Liang 15429fbc61f8SKan Liang free_name: 154357f14b5aSArnaldo Carvalho de Melo zfree(&caps->name); 15449fbc61f8SKan Liang free_caps: 15459fbc61f8SKan Liang free(caps); 15469fbc61f8SKan Liang 15479fbc61f8SKan Liang return -ENOMEM; 15489fbc61f8SKan Liang } 15499fbc61f8SKan Liang 1550eec11310SNamhyung Kim static void perf_pmu__del_caps(struct perf_pmu *pmu) 1551eec11310SNamhyung Kim { 1552eec11310SNamhyung Kim struct perf_pmu_caps *caps, *tmp; 1553eec11310SNamhyung Kim 1554eec11310SNamhyung Kim list_for_each_entry_safe(caps, tmp, &pmu->caps, list) { 1555eec11310SNamhyung Kim list_del(&caps->list); 1556efe98a7aSArnaldo Carvalho de Melo zfree(&caps->name); 1557efe98a7aSArnaldo Carvalho de Melo zfree(&caps->value); 1558eec11310SNamhyung Kim free(caps); 1559eec11310SNamhyung Kim } 1560eec11310SNamhyung Kim } 1561eec11310SNamhyung Kim 15629fbc61f8SKan Liang /* 15639fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 15649fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 15659fbc61f8SKan Liang * Return the number of capabilities 15669fbc61f8SKan Liang */ 15679fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 15689fbc61f8SKan Liang { 15699fbc61f8SKan Liang struct stat st; 15709fbc61f8SKan Liang char caps_path[PATH_MAX]; 15719fbc61f8SKan Liang DIR *caps_dir; 15729fbc61f8SKan Liang struct dirent *evt_ent; 1573b39094d3SNamhyung Kim int caps_fd; 15743339ec44SRavi Bangoria 15753339ec44SRavi Bangoria if (pmu->caps_initialized) 15763339ec44SRavi Bangoria return pmu->nr_caps; 15773339ec44SRavi Bangoria 15783339ec44SRavi Bangoria pmu->nr_caps = 0; 15799fbc61f8SKan Liang 1580f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name, "caps")) 15819fbc61f8SKan Liang return -1; 15829fbc61f8SKan Liang 15833339ec44SRavi Bangoria if (stat(caps_path, &st) < 0) { 15843339ec44SRavi Bangoria pmu->caps_initialized = true; 15859fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 15863339ec44SRavi Bangoria } 15879fbc61f8SKan Liang 15889fbc61f8SKan Liang caps_dir = opendir(caps_path); 15899fbc61f8SKan Liang if (!caps_dir) 15909fbc61f8SKan Liang return -EINVAL; 15919fbc61f8SKan Liang 1592b39094d3SNamhyung Kim caps_fd = dirfd(caps_dir); 1593b39094d3SNamhyung Kim 15949fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 15959fbc61f8SKan Liang char *name = evt_ent->d_name; 15969fbc61f8SKan Liang char value[128]; 15979fbc61f8SKan Liang FILE *file; 1598b39094d3SNamhyung Kim int fd; 15999fbc61f8SKan Liang 16009fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 16019fbc61f8SKan Liang continue; 16029fbc61f8SKan Liang 1603b39094d3SNamhyung Kim fd = openat(caps_fd, name, O_RDONLY); 16040ea8920eSIan Rogers if (fd == -1) 16059fbc61f8SKan Liang continue; 16060ea8920eSIan Rogers file = fdopen(fd, "r"); 16070ea8920eSIan Rogers if (!file) { 16080ea8920eSIan Rogers close(fd); 16090ea8920eSIan Rogers continue; 16100ea8920eSIan Rogers } 16119fbc61f8SKan Liang 16129fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 16139fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 16149fbc61f8SKan Liang fclose(file); 16159fbc61f8SKan Liang continue; 16169fbc61f8SKan Liang } 16179fbc61f8SKan Liang 16183339ec44SRavi Bangoria pmu->nr_caps++; 16199fbc61f8SKan Liang fclose(file); 16209fbc61f8SKan Liang } 16219fbc61f8SKan Liang 16229fbc61f8SKan Liang closedir(caps_dir); 16239fbc61f8SKan Liang 16243339ec44SRavi Bangoria pmu->caps_initialized = true; 16253339ec44SRavi Bangoria return pmu->nr_caps; 16269fbc61f8SKan Liang } 1627e4064776SJin Yao 1628b9f01032SIan Rogers static void perf_pmu__compute_config_masks(struct perf_pmu *pmu) 1629e4064776SJin Yao { 1630e4064776SJin Yao struct perf_pmu_format *format; 1631b9f01032SIan Rogers 1632b9f01032SIan Rogers if (pmu->config_masks_computed) 1633b9f01032SIan Rogers return; 1634e4064776SJin Yao 1635e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1636b9f01032SIan Rogers unsigned int i; 1637b9f01032SIan Rogers __u64 *mask; 1638b9f01032SIan Rogers 1639b9f01032SIan Rogers if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) 1640e4064776SJin Yao continue; 1641e4064776SJin Yao 1642b9f01032SIan Rogers pmu->config_masks_present = true; 1643b9f01032SIan Rogers mask = &pmu->config_masks[format->value]; 1644b9f01032SIan Rogers 1645e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1646b9f01032SIan Rogers *mask |= 1ULL << i; 1647e4064776SJin Yao } 1648b9f01032SIan Rogers pmu->config_masks_computed = true; 1649b9f01032SIan Rogers } 1650b9f01032SIan Rogers 1651b9f01032SIan Rogers void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 1652b9f01032SIan Rogers const char *name, int config_num, 1653b9f01032SIan Rogers const char *config_name) 1654b9f01032SIan Rogers { 1655b9f01032SIan Rogers __u64 bits; 1656b9f01032SIan Rogers char buf[100]; 1657b9f01032SIan Rogers 1658b9f01032SIan Rogers perf_pmu__compute_config_masks(pmu); 1659e4064776SJin Yao 1660e4064776SJin Yao /* 1661e4064776SJin Yao * Kernel doesn't export any valid format bits. 1662e4064776SJin Yao */ 1663b9f01032SIan Rogers if (!pmu->config_masks_present) 1664e4064776SJin Yao return; 1665e4064776SJin Yao 1666b9f01032SIan Rogers bits = config & ~pmu->config_masks[config_num]; 1667e4064776SJin Yao if (bits == 0) 1668e4064776SJin Yao return; 1669e4064776SJin Yao 1670e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1671e4064776SJin Yao 1672b9f01032SIan Rogers pr_warning("WARNING: event '%s' not valid (bits %s of %s " 1673e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1674b9f01032SIan Rogers name ?: "N/A", buf, config_name, config); 1675e4064776SJin Yao } 1676c5a26ea4SJin Yao 1677c47a5599SJin Yao int perf_pmu__match(char *pattern, char *name, char *tok) 1678c47a5599SJin Yao { 167913d60ba0SKan Liang if (!name) 168013d60ba0SKan Liang return -1; 168113d60ba0SKan Liang 1682c47a5599SJin Yao if (fnmatch(pattern, name, 0)) 1683c47a5599SJin Yao return -1; 1684c47a5599SJin Yao 1685240e6fd0SIan Rogers if (tok && !perf_pmu__match_ignoring_suffix(name, tok)) 1686c47a5599SJin Yao return -1; 1687c47a5599SJin Yao 1688c47a5599SJin Yao return 0; 1689c47a5599SJin Yao } 16901d3351e6SJin Yao 1691acef233bSJing Zhang double __weak perf_pmu__cpu_slots_per_cycle(void) 1692acef233bSJing Zhang { 1693acef233bSJing Zhang return NAN; 1694acef233bSJing Zhang } 1695f8ad6018SJames Clark 1696f8ad6018SJames Clark int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size) 1697f8ad6018SJames Clark { 1698f8ad6018SJames Clark const char *sysfs = sysfs__mountpoint(); 1699f8ad6018SJames Clark 1700f8ad6018SJames Clark if (!sysfs) 1701f8ad6018SJames Clark return 0; 1702f8ad6018SJames Clark return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs); 1703f8ad6018SJames Clark } 1704f8ad6018SJames Clark 1705e293a5e8SNamhyung Kim int perf_pmu__event_source_devices_fd(void) 1706e293a5e8SNamhyung Kim { 1707e293a5e8SNamhyung Kim char path[PATH_MAX]; 1708e293a5e8SNamhyung Kim const char *sysfs = sysfs__mountpoint(); 1709e293a5e8SNamhyung Kim 1710e293a5e8SNamhyung Kim if (!sysfs) 1711e293a5e8SNamhyung Kim return -1; 1712e293a5e8SNamhyung Kim 1713e293a5e8SNamhyung Kim scnprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs); 1714e293a5e8SNamhyung Kim return open(path, O_DIRECTORY); 1715e293a5e8SNamhyung Kim } 1716e293a5e8SNamhyung Kim 1717f8ad6018SJames Clark /* 1718f8ad6018SJames Clark * Fill 'buf' with the path to a file or folder in 'pmu_name' in 1719f8ad6018SJames Clark * sysfs. For example if pmu_name = "cs_etm" and 'filename' = "format" 1720f8ad6018SJames Clark * then pathname will be filled with 1721f8ad6018SJames Clark * "/sys/bus/event_source/devices/cs_etm/format" 1722f8ad6018SJames Clark * 1723f8ad6018SJames Clark * Return 0 if the sysfs mountpoint couldn't be found or if no 1724f8ad6018SJames Clark * characters were written. 1725f8ad6018SJames Clark */ 1726f8ad6018SJames Clark int perf_pmu__pathname_scnprintf(char *buf, size_t size, 1727f8ad6018SJames Clark const char *pmu_name, const char *filename) 1728f8ad6018SJames Clark { 1729f8ad6018SJames Clark char base_path[PATH_MAX]; 1730f8ad6018SJames Clark 1731f8ad6018SJames Clark if (!perf_pmu__event_source_devices_scnprintf(base_path, sizeof(base_path))) 1732f8ad6018SJames Clark return 0; 1733f8ad6018SJames Clark return scnprintf(buf, size, "%s%s/%s", base_path, pmu_name, filename); 1734f8ad6018SJames Clark } 1735eec11310SNamhyung Kim 1736e293a5e8SNamhyung Kim int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags) 1737e293a5e8SNamhyung Kim { 1738e293a5e8SNamhyung Kim char path[PATH_MAX]; 1739e293a5e8SNamhyung Kim 1740e293a5e8SNamhyung Kim scnprintf(path, sizeof(path), "%s/%s", pmu_name, filename); 1741e293a5e8SNamhyung Kim return openat(dirfd, path, flags); 1742e293a5e8SNamhyung Kim } 1743e293a5e8SNamhyung Kim 17441eaf496eSIan Rogers void perf_pmu__delete(struct perf_pmu *pmu) 1745eec11310SNamhyung Kim { 1746eec11310SNamhyung Kim perf_pmu__del_formats(&pmu->format); 1747eec11310SNamhyung Kim perf_pmu__del_aliases(pmu); 1748eec11310SNamhyung Kim perf_pmu__del_caps(pmu); 1749eec11310SNamhyung Kim 1750eec11310SNamhyung Kim perf_cpu_map__put(pmu->cpus); 1751eec11310SNamhyung Kim 1752efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->default_config); 1753efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->name); 1754efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->alias_name); 1755eec11310SNamhyung Kim free(pmu); 1756eec11310SNamhyung Kim } 1757