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 */ 5543a69672eSNamhyung Kim static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name) 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 578a0c41caeSIan Rogers return !strcmp(name, "cpu") ? perf_cpu_map__get(cpu_map__online()) : NULL; 57966ec1191SMark Rutland } 5807ae92e74SYan, Zheng 5813a69672eSNamhyung Kim static bool pmu_is_uncore(int dirfd, const char *name) 58266ec1191SMark Rutland { 5833a69672eSNamhyung Kim int fd; 5847ae92e74SYan, Zheng 5853a69672eSNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "cpumask", O_PATH); 5863a69672eSNamhyung Kim if (fd < 0) 5873a69672eSNamhyung Kim return false; 5883a69672eSNamhyung Kim 5893a69672eSNamhyung Kim close(fd); 5903a69672eSNamhyung Kim return true; 5917ae92e74SYan, Zheng } 5927ae92e74SYan, Zheng 59351d54847SJohn Garry static char *pmu_id(const char *name) 59451d54847SJohn Garry { 59551d54847SJohn Garry char path[PATH_MAX], *str; 59651d54847SJohn Garry size_t len; 59751d54847SJohn Garry 5985f2c8efaSJames Clark perf_pmu__pathname_scnprintf(path, sizeof(path), name, "identifier"); 59951d54847SJohn Garry 6005f2c8efaSJames Clark if (filename__read_str(path, &str, &len) < 0) 60151d54847SJohn Garry return NULL; 60251d54847SJohn Garry 60351d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 60451d54847SJohn Garry 60551d54847SJohn Garry return str; 60651d54847SJohn Garry } 60751d54847SJohn Garry 6084bf7e81aSIan Rogers /** 6094bf7e81aSIan Rogers * is_sysfs_pmu_core() - PMU CORE devices have different name other than cpu in 6104bf7e81aSIan Rogers * sysfs on some platforms like ARM or Intel hybrid. Looking for 6114bf7e81aSIan Rogers * possible the cpus file in sysfs files to identify whether this is a 6124bf7e81aSIan Rogers * core device. 6134bf7e81aSIan Rogers * @name: The PMU name such as "cpu_atom". 61414b22ae0SGanapatrao Kulkarni */ 6154bf7e81aSIan Rogers static int is_sysfs_pmu_core(const char *name) 61614b22ae0SGanapatrao Kulkarni { 61714b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 61814b22ae0SGanapatrao Kulkarni 619f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpus")) 62014b22ae0SGanapatrao Kulkarni return 0; 621d9664582SAndi Kleen return file_available(path); 62214b22ae0SGanapatrao Kulkarni } 62314b22ae0SGanapatrao Kulkarni 62429be2fe0SIan Rogers char *perf_pmu__getcpuid(struct perf_pmu *pmu) 625d77ade9fSAndi Kleen { 626d77ade9fSAndi Kleen char *cpuid; 627d77ade9fSAndi Kleen static bool printed; 628d77ade9fSAndi Kleen 629d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 630d77ade9fSAndi Kleen if (cpuid) 631d77ade9fSAndi Kleen cpuid = strdup(cpuid); 632d77ade9fSAndi Kleen if (!cpuid) 63354e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 634d77ade9fSAndi Kleen if (!cpuid) 635d77ade9fSAndi Kleen return NULL; 636d77ade9fSAndi Kleen 637d77ade9fSAndi Kleen if (!printed) { 638d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 639d77ade9fSAndi Kleen printed = true; 640d77ade9fSAndi Kleen } 641d77ade9fSAndi Kleen return cpuid; 642d77ade9fSAndi Kleen } 643d77ade9fSAndi Kleen 6441ba3752aSIan Rogers __weak const struct pmu_events_table *pmu_events_table__find(void) 645e126bef5SJohn Garry { 64696d2a746SIan Rogers return perf_pmu__find_events_table(NULL); 647e126bef5SJohn Garry } 648e126bef5SJohn Garry 649f8ea2c15SIan Rogers __weak const struct pmu_metrics_table *pmu_metrics_table__find(void) 650f8ea2c15SIan Rogers { 651f8ea2c15SIan Rogers return perf_pmu__find_metrics_table(NULL); 652f8ea2c15SIan Rogers } 653f8ea2c15SIan Rogers 654240e6fd0SIan Rogers /** 655240e6fd0SIan Rogers * perf_pmu__match_ignoring_suffix - Does the pmu_name match tok ignoring any 656240e6fd0SIan Rogers * trailing suffix? The Suffix must be in form 657240e6fd0SIan Rogers * tok_{digits}, or tok{digits}. 658240e6fd0SIan Rogers * @pmu_name: The pmu_name with possible suffix. 659240e6fd0SIan Rogers * @tok: The possible match to pmu_name without suffix. 660c07d5c92SJohn Garry */ 661240e6fd0SIan Rogers static bool perf_pmu__match_ignoring_suffix(const char *pmu_name, const char *tok) 662c47a5599SJin Yao { 663c07d5c92SJohn Garry const char *p; 664c47a5599SJin Yao 665c47a5599SJin Yao if (strncmp(pmu_name, tok, strlen(tok))) 666c47a5599SJin Yao return false; 667c47a5599SJin Yao 668c47a5599SJin Yao p = pmu_name + strlen(tok); 669c47a5599SJin Yao if (*p == 0) 670c47a5599SJin Yao return true; 671c47a5599SJin Yao 672c07d5c92SJohn Garry if (*p == '_') 673c47a5599SJin Yao ++p; 674c07d5c92SJohn Garry 675c07d5c92SJohn Garry /* Ensure we end in a number */ 676c07d5c92SJohn Garry while (1) { 677c07d5c92SJohn Garry if (!isdigit(*p)) 678c47a5599SJin Yao return false; 679c07d5c92SJohn Garry if (*(++p) == 0) 680c07d5c92SJohn Garry break; 681c07d5c92SJohn Garry } 682c47a5599SJin Yao 683c47a5599SJin Yao return true; 684c47a5599SJin Yao } 685c47a5599SJin Yao 686240e6fd0SIan Rogers /** 687240e6fd0SIan Rogers * pmu_uncore_alias_match - does name match the PMU name? 688240e6fd0SIan Rogers * @pmu_name: the json struct pmu_event name. This may lack a suffix (which 689240e6fd0SIan Rogers * matches) or be of the form "socket,pmuname" which will match 690240e6fd0SIan Rogers * "socketX_pmunameY". 691240e6fd0SIan Rogers * @name: a real full PMU name as from sysfs. 692240e6fd0SIan Rogers */ 693240e6fd0SIan Rogers static bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 694730670b1SJohn Garry { 695730670b1SJohn Garry char *tmp = NULL, *tok, *str; 696730670b1SJohn Garry bool res; 697730670b1SJohn Garry 698240e6fd0SIan Rogers if (strchr(pmu_name, ',') == NULL) 699240e6fd0SIan Rogers return perf_pmu__match_ignoring_suffix(name, pmu_name); 700240e6fd0SIan Rogers 701730670b1SJohn Garry str = strdup(pmu_name); 702730670b1SJohn Garry if (!str) 703730670b1SJohn Garry return false; 704730670b1SJohn Garry 705730670b1SJohn Garry /* 706730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 707730670b1SJohn Garry */ 708730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 709730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 710730670b1SJohn Garry res = false; 711730670b1SJohn Garry goto out; 712730670b1SJohn Garry } 713730670b1SJohn Garry 714730670b1SJohn Garry /* 715730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 716730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 717730670b1SJohn Garry * 718730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 719730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 720730670b1SJohn Garry * "pmunameY". 721730670b1SJohn Garry */ 722c07d5c92SJohn Garry while (1) { 723c07d5c92SJohn Garry char *next_tok = strtok_r(NULL, ",", &tmp); 724c07d5c92SJohn Garry 725730670b1SJohn Garry name = strstr(name, tok); 726c07d5c92SJohn Garry if (!name || 727240e6fd0SIan Rogers (!next_tok && !perf_pmu__match_ignoring_suffix(name, tok))) { 728730670b1SJohn Garry res = false; 729730670b1SJohn Garry goto out; 730730670b1SJohn Garry } 731c07d5c92SJohn Garry if (!next_tok) 732c07d5c92SJohn Garry break; 733c07d5c92SJohn Garry tok = next_tok; 734c07d5c92SJohn Garry name += strlen(tok); 735730670b1SJohn Garry } 736730670b1SJohn Garry 737730670b1SJohn Garry res = true; 738730670b1SJohn Garry out: 739730670b1SJohn Garry free(str); 740730670b1SJohn Garry return res; 741730670b1SJohn Garry } 742730670b1SJohn Garry 743660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data { 744660842e4SIan Rogers struct list_head *head; 745660842e4SIan Rogers const char *name; 746660842e4SIan Rogers const char *cpu_name; 747660842e4SIan Rogers struct perf_pmu *pmu; 748660842e4SIan Rogers }; 749660842e4SIan Rogers 750660842e4SIan Rogers static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, 7511ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 752660842e4SIan Rogers void *vdata) 753660842e4SIan Rogers { 754660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data *data = vdata; 755660842e4SIan Rogers const char *pname = pe->pmu ? pe->pmu : data->cpu_name; 756660842e4SIan Rogers 757660842e4SIan Rogers if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name)) 758660842e4SIan Rogers goto new_alias; 759660842e4SIan Rogers 760660842e4SIan Rogers if (strcmp(pname, data->name)) 761660842e4SIan Rogers return 0; 762660842e4SIan Rogers 763660842e4SIan Rogers new_alias: 764660842e4SIan Rogers /* need type casts to override 'const' */ 765e293a5e8SNamhyung Kim __perf_pmu__new_alias(data->head, -1, (char *)pe->name, (char *)pe->desc, 766660842e4SIan Rogers (char *)pe->event, pe); 767660842e4SIan Rogers return 0; 768660842e4SIan Rogers } 769660842e4SIan Rogers 770933f82ffSSukadev Bhattiprolu /* 771933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 772933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 773933f82ffSSukadev Bhattiprolu * as aliases. 774933f82ffSSukadev Bhattiprolu */ 775eeac7730SIan Rogers void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu, 7761ba3752aSIan Rogers const struct pmu_events_table *table) 777933f82ffSSukadev Bhattiprolu { 778660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data data = { 779660842e4SIan Rogers .head = head, 780660842e4SIan Rogers .name = pmu->name, 7814bf7e81aSIan Rogers .cpu_name = is_sysfs_pmu_core(pmu->name) ? pmu->name : "cpu", 782660842e4SIan Rogers .pmu = pmu, 783660842e4SIan Rogers }; 784fedb2b51SAndi Kleen 785660842e4SIan Rogers pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data); 786933f82ffSSukadev Bhattiprolu } 787933f82ffSSukadev Bhattiprolu 788e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 789e45ad701SJohn Garry { 7901ba3752aSIan Rogers const struct pmu_events_table *table; 791e45ad701SJohn Garry 79296d2a746SIan Rogers table = perf_pmu__find_events_table(pmu); 793eeac7730SIan Rogers if (!table) 794e45ad701SJohn Garry return; 795e45ad701SJohn Garry 796eeac7730SIan Rogers pmu_add_cpu_aliases_table(head, pmu, table); 797e45ad701SJohn Garry } 798e45ad701SJohn Garry 7994513c719SJohn Garry struct pmu_sys_event_iter_data { 8004513c719SJohn Garry struct list_head *head; 8014513c719SJohn Garry struct perf_pmu *pmu; 8024513c719SJohn Garry }; 8034513c719SJohn Garry 80429be2fe0SIan Rogers static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, 8051ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 80629be2fe0SIan Rogers void *data) 8074513c719SJohn Garry { 8084513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8094513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8104513c719SJohn Garry 8114513c719SJohn Garry if (!pe->compat || !pe->pmu) 8124513c719SJohn Garry return 0; 8134513c719SJohn Garry 8144513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8154513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 816e293a5e8SNamhyung Kim __perf_pmu__new_alias(idata->head, -1, 8174513c719SJohn Garry (char *)pe->name, 8184513c719SJohn Garry (char *)pe->desc, 8194513c719SJohn Garry (char *)pe->event, 820eab35953SJin Yao pe); 8214513c719SJohn Garry } 8224513c719SJohn Garry 8234513c719SJohn Garry return 0; 8244513c719SJohn Garry } 8254513c719SJohn Garry 826e199f47fSJohn Garry void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 8274513c719SJohn Garry { 8284513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 8294513c719SJohn Garry .head = head, 8304513c719SJohn Garry .pmu = pmu, 8314513c719SJohn Garry }; 8324513c719SJohn Garry 8334513c719SJohn Garry if (!pmu->id) 8344513c719SJohn Garry return; 8354513c719SJohn Garry 8364513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 8374513c719SJohn Garry } 8384513c719SJohn Garry 839c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 840dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 841dc0a6202SAdrian Hunter { 842dc0a6202SAdrian Hunter return NULL; 843dc0a6202SAdrian Hunter } 844dc0a6202SAdrian Hunter 84513d60ba0SKan Liang char * __weak 84613d60ba0SKan Liang pmu_find_real_name(const char *name) 84713d60ba0SKan Liang { 84813d60ba0SKan Liang return (char *)name; 84913d60ba0SKan Liang } 85013d60ba0SKan Liang 85113d60ba0SKan Liang char * __weak 85213d60ba0SKan Liang pmu_find_alias_name(const char *name __maybe_unused) 85313d60ba0SKan Liang { 85413d60ba0SKan Liang return NULL; 85513d60ba0SKan Liang } 85613d60ba0SKan Liang 8573a69672eSNamhyung Kim static int pmu_max_precise(int dirfd, struct perf_pmu *pmu) 85890a86bdeSJiri Olsa { 85990a86bdeSJiri Olsa int max_precise = -1; 86090a86bdeSJiri Olsa 8613a69672eSNamhyung Kim perf_pmu__scan_file_at(pmu, dirfd, "caps/max_precise", "%d", &max_precise); 86290a86bdeSJiri Olsa return max_precise; 86390a86bdeSJiri Olsa } 86490a86bdeSJiri Olsa 8651eaf496eSIan Rogers struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name) 866cd82a32eSJiri Olsa { 867cd82a32eSJiri Olsa struct perf_pmu *pmu; 868cd82a32eSJiri Olsa LIST_HEAD(format); 869a6146d50SZheng Yan LIST_HEAD(aliases); 870cd82a32eSJiri Olsa __u32 type; 87113d60ba0SKan Liang char *name = pmu_find_real_name(lookup_name); 87213d60ba0SKan Liang char *alias_name; 87349afa7f6SJin Yao 87449afa7f6SJin Yao /* 875cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 876cd82a32eSJiri Olsa * type value and format definitions. Load both right 877cd82a32eSJiri Olsa * now. 878cd82a32eSJiri Olsa */ 879e293a5e8SNamhyung Kim if (pmu_format(dirfd, name, &format)) 880cd82a32eSJiri Olsa return NULL; 881cd82a32eSJiri Olsa 88215b22ed3SAndi Kleen /* 883f8ad6018SJames Clark * Check the aliases first to avoid unnecessary work. 88415b22ed3SAndi Kleen */ 885e293a5e8SNamhyung Kim if (pmu_aliases(dirfd, name, &aliases)) 8863fded963SJiri Olsa return NULL; 8873fded963SJiri Olsa 888cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 889cd82a32eSJiri Olsa if (!pmu) 890cd82a32eSJiri Olsa return NULL; 891cd82a32eSJiri Olsa 8923a69672eSNamhyung Kim pmu->cpus = pmu_cpumask(dirfd, name); 89354e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 89413d60ba0SKan Liang if (!pmu->name) 89513d60ba0SKan Liang goto err; 89613d60ba0SKan Liang 897f8ad6018SJames Clark /* Read type, and ensure that type value is successfully assigned (return 1) */ 8983a69672eSNamhyung Kim if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &type) != 1) 899f8ad6018SJames Clark goto err; 900f8ad6018SJames Clark 90113d60ba0SKan Liang alias_name = pmu_find_alias_name(name); 90213d60ba0SKan Liang if (alias_name) { 90313d60ba0SKan Liang pmu->alias_name = strdup(alias_name); 90413d60ba0SKan Liang if (!pmu->alias_name) 90513d60ba0SKan Liang goto err; 90613d60ba0SKan Liang } 90713d60ba0SKan Liang 90854e32dc0SGanapatrao Kulkarni pmu->type = type; 909e20d1f2fSIan Rogers pmu->is_core = is_pmu_core(name); 9103a69672eSNamhyung Kim pmu->is_uncore = pmu_is_uncore(dirfd, name); 91151d54847SJohn Garry if (pmu->is_uncore) 91251d54847SJohn Garry pmu->id = pmu_id(name); 9133a69672eSNamhyung Kim pmu->max_precise = pmu_max_precise(dirfd, pmu); 91454e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 9154513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 91666ec1191SMark Rutland 917cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 918a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 9199fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 920cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 921a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 9221eaf496eSIan Rogers list_add_tail(&pmu->list, pmus); 923dc0a6202SAdrian Hunter 924dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 925dc0a6202SAdrian Hunter 926cd82a32eSJiri Olsa return pmu; 92713d60ba0SKan Liang err: 928efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->name); 92913d60ba0SKan Liang free(pmu); 93013d60ba0SKan Liang return NULL; 931cd82a32eSJiri Olsa } 932cd82a32eSJiri Olsa 933e552b7beSRob Herring void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) 934e552b7beSRob Herring { 935e552b7beSRob Herring struct perf_pmu_format *format; 936e552b7beSRob Herring 937*68c25043SIan Rogers if (pmu->formats_checked) 938*68c25043SIan Rogers return; 939*68c25043SIan Rogers 940*68c25043SIan Rogers pmu->formats_checked = true; 941*68c25043SIan Rogers 942e552b7beSRob Herring /* fake pmu doesn't have format list */ 943e552b7beSRob Herring if (pmu == &perf_pmu__fake) 944e552b7beSRob Herring return; 945e552b7beSRob Herring 946e552b7beSRob Herring list_for_each_entry(format, &pmu->format, list) 947e552b7beSRob Herring if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) { 948e552b7beSRob Herring pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'" 949e552b7beSRob Herring "which is not supported by this version of perf!\n", 950e552b7beSRob Herring pmu->name, format->name, format->value); 951e552b7beSRob Herring return; 952e552b7beSRob Herring } 953e552b7beSRob Herring } 954e552b7beSRob Herring 955c6d616feSIan Rogers bool evsel__is_aux_event(const struct evsel *evsel) 956e12ee9f7SAdrian Hunter { 957e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 958e12ee9f7SAdrian Hunter 959e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 960e12ee9f7SAdrian Hunter } 961e12ee9f7SAdrian Hunter 9626593f019SJames Clark /* 9636593f019SJames Clark * Set @config_name to @val as long as the user hasn't already set or cleared it 9646593f019SJames Clark * by passing a config term on the command line. 9656593f019SJames Clark * 9666593f019SJames Clark * @val is the value to put into the bits specified by @config_name rather than 9676593f019SJames Clark * the bit pattern. It is shifted into position by this function, so to set 9686593f019SJames Clark * something to true, pass 1 for val rather than a pre shifted value. 9696593f019SJames Clark */ 9706593f019SJames Clark #define field_prep(_mask, _val) (((_val) << (ffsll(_mask) - 1)) & (_mask)) 9716593f019SJames Clark void evsel__set_config_if_unset(struct perf_pmu *pmu, struct evsel *evsel, 9726593f019SJames Clark const char *config_name, u64 val) 9736593f019SJames Clark { 9746593f019SJames Clark u64 user_bits = 0, bits; 9756593f019SJames Clark struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG); 9766593f019SJames Clark 9776593f019SJames Clark if (term) 9786593f019SJames Clark user_bits = term->val.cfg_chg; 9796593f019SJames Clark 9806593f019SJames Clark bits = perf_pmu__format_bits(&pmu->format, config_name); 9816593f019SJames Clark 9826593f019SJames Clark /* Do nothing if the user changed the value */ 9836593f019SJames Clark if (bits & user_bits) 9846593f019SJames Clark return; 9856593f019SJames Clark 9866593f019SJames Clark /* Otherwise replace it */ 9876593f019SJames Clark evsel->core.attr.config &= ~bits; 9886593f019SJames Clark evsel->core.attr.config |= field_prep(bits, val); 9896593f019SJames Clark } 9906593f019SJames Clark 9915c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 99209ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 993cd82a32eSJiri Olsa { 9945c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 995cd82a32eSJiri Olsa 996cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 997cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 998cd82a32eSJiri Olsa return format; 999cd82a32eSJiri Olsa 1000cd82a32eSJiri Olsa return NULL; 1001cd82a32eSJiri Olsa } 1002cd82a32eSJiri Olsa 100309ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 100409ff6071SAdrian Hunter { 100509ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 100609ff6071SAdrian Hunter __u64 bits = 0; 100709ff6071SAdrian Hunter int fbit; 100809ff6071SAdrian Hunter 100909ff6071SAdrian Hunter if (!format) 101009ff6071SAdrian Hunter return 0; 101109ff6071SAdrian Hunter 101209ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 101309ff6071SAdrian Hunter bits |= 1ULL << fbit; 101409ff6071SAdrian Hunter 101509ff6071SAdrian Hunter return bits; 101609ff6071SAdrian Hunter } 101709ff6071SAdrian Hunter 1018a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1019a1ac7de6SAdrian Hunter { 1020a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1021a1ac7de6SAdrian Hunter 1022a1ac7de6SAdrian Hunter if (!format) 1023a1ac7de6SAdrian Hunter return -1; 1024a1ac7de6SAdrian Hunter 1025a1ac7de6SAdrian Hunter return format->value; 1026a1ac7de6SAdrian Hunter } 1027a1ac7de6SAdrian Hunter 1028cd82a32eSJiri Olsa /* 1029dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 10304d39c89fSIngo Molnar * and unformatted value (value parameter). 1031cd82a32eSJiri Olsa */ 1032dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1033dc0a6202SAdrian Hunter bool zero) 1034cd82a32eSJiri Olsa { 1035cd82a32eSJiri Olsa unsigned long fbit, vbit; 1036cd82a32eSJiri Olsa 1037cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1038cd82a32eSJiri Olsa 1039cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1040cd82a32eSJiri Olsa continue; 1041cd82a32eSJiri Olsa 1042dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1043dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1044dc0a6202SAdrian Hunter else if (zero) 1045dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1046cd82a32eSJiri Olsa } 1047cd82a32eSJiri Olsa } 1048cd82a32eSJiri Olsa 10490efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 10500efe6b67SAdrian Hunter { 10511b9caa10SJiri Olsa int w; 10520efe6b67SAdrian Hunter 10531b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 10541b9caa10SJiri Olsa if (!w) 10551b9caa10SJiri Olsa return 0; 10561b9caa10SJiri Olsa if (w < 64) 10571b9caa10SJiri Olsa return (1ULL << w) - 1; 10581b9caa10SJiri Olsa return -1; 10590efe6b67SAdrian Hunter } 10600efe6b67SAdrian Hunter 1061cd82a32eSJiri Olsa /* 1062688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1063688d4dfcSCody P Schafer * in the remaining terms. 1064688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1065688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1066688d4dfcSCody P Schafer * in a config string) later on in the term list. 1067688d4dfcSCody P Schafer */ 1068688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1069688d4dfcSCody P Schafer struct list_head *head_terms, 1070688d4dfcSCody P Schafer __u64 *value) 1071688d4dfcSCody P Schafer { 1072688d4dfcSCody P Schafer struct parse_events_term *t; 1073688d4dfcSCody P Schafer 1074688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 10752a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 10762a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1077688d4dfcSCody P Schafer t->used = true; 1078688d4dfcSCody P Schafer *value = t->val.num; 1079688d4dfcSCody P Schafer return 0; 1080688d4dfcSCody P Schafer } 1081688d4dfcSCody P Schafer } 1082688d4dfcSCody P Schafer 1083bb963e16SNamhyung Kim if (verbose > 0) 1084688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1085688d4dfcSCody P Schafer 1086688d4dfcSCody P Schafer return -1; 1087688d4dfcSCody P Schafer } 1088688d4dfcSCody P Schafer 1089ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1090e64b020bSJiri Olsa { 1091e64b020bSJiri Olsa struct perf_pmu_format *format; 109211db4e29SMasami Hiramatsu char *str = NULL; 109311db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1094f1417ceaSXin Gao unsigned int i = 0; 1095e64b020bSJiri Olsa 1096ffeb883eSHe Kuang if (!formats) 1097e64b020bSJiri Olsa return NULL; 1098e64b020bSJiri Olsa 1099e64b020bSJiri Olsa /* sysfs exported terms */ 1100ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 110111db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 110211db4e29SMasami Hiramatsu goto error; 1103e64b020bSJiri Olsa 1104ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 110511db4e29SMasami Hiramatsu error: 1106ffeb883eSHe Kuang strbuf_release(&buf); 1107e64b020bSJiri Olsa 1108e64b020bSJiri Olsa return str; 1109e64b020bSJiri Olsa } 1110e64b020bSJiri Olsa 1111688d4dfcSCody P Schafer /* 1112cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 111388aca8d9SCody P Schafer * user input data - term parameter. 1114cd82a32eSJiri Olsa */ 11154ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 11164ac22b48SIan Rogers struct list_head *formats, 1117cd82a32eSJiri Olsa struct perf_event_attr *attr, 1118dc0a6202SAdrian Hunter struct parse_events_term *term, 1119688d4dfcSCody P Schafer struct list_head *head_terms, 1120e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1121cd82a32eSJiri Olsa { 11225c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1123cd82a32eSJiri Olsa __u64 *vp; 11240efe6b67SAdrian Hunter __u64 val, max_val; 1125cd82a32eSJiri Olsa 1126cd82a32eSJiri Olsa /* 1127688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1128688d4dfcSCody P Schafer * skip it in normal eval. 1129688d4dfcSCody P Schafer */ 1130688d4dfcSCody P Schafer if (term->used) 1131688d4dfcSCody P Schafer return 0; 1132688d4dfcSCody P Schafer 1133688d4dfcSCody P Schafer /* 1134cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1135cd82a32eSJiri Olsa * to be done for them. 1136cd82a32eSJiri Olsa */ 1137cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1138cd82a32eSJiri Olsa return 0; 1139cd82a32eSJiri Olsa 1140cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1141688d4dfcSCody P Schafer if (!format) { 1142ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 11434ac22b48SIan Rogers char *unknown_term; 11444ac22b48SIan Rogers char *help_msg; 1145ffeb883eSHe Kuang 11464ac22b48SIan Rogers if (asprintf(&unknown_term, 11474ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 11484ac22b48SIan Rogers term->config, pmu_name) < 0) 11494ac22b48SIan Rogers unknown_term = NULL; 11504ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 11514ac22b48SIan Rogers if (err) { 11526c191289SIan Rogers parse_events_error__handle(err, term->err_term, 11534ac22b48SIan Rogers unknown_term, 11544ac22b48SIan Rogers help_msg); 11554ac22b48SIan Rogers } else { 11564ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 11574ac22b48SIan Rogers free(unknown_term); 1158e64b020bSJiri Olsa } 11594ac22b48SIan Rogers free(pmu_term); 1160cd82a32eSJiri Olsa return -EINVAL; 1161688d4dfcSCody P Schafer } 1162cd82a32eSJiri Olsa 1163cd82a32eSJiri Olsa switch (format->value) { 1164cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1165cd82a32eSJiri Olsa vp = &attr->config; 1166cd82a32eSJiri Olsa break; 1167cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1168cd82a32eSJiri Olsa vp = &attr->config1; 1169cd82a32eSJiri Olsa break; 1170cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1171cd82a32eSJiri Olsa vp = &attr->config2; 1172cd82a32eSJiri Olsa break; 1173204e7c49SRob Herring case PERF_PMU_FORMAT_VALUE_CONFIG3: 1174204e7c49SRob Herring vp = &attr->config3; 1175204e7c49SRob Herring break; 1176cd82a32eSJiri Olsa default: 1177cd82a32eSJiri Olsa return -EINVAL; 1178cd82a32eSJiri Olsa } 1179cd82a32eSJiri Olsa 118016fa7e82SJiri Olsa /* 1181688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1182688d4dfcSCody P Schafer * using event parameters. 118316fa7e82SJiri Olsa */ 118499e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 118599e7138eSJiri Olsa if (term->no_value && 118699e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 118799e7138eSJiri Olsa if (err) { 11886c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1189448d732cSIan Rogers strdup("no value assigned for term"), 1190448d732cSIan Rogers NULL); 119199e7138eSJiri Olsa } 119299e7138eSJiri Olsa return -EINVAL; 119399e7138eSJiri Olsa } 119499e7138eSJiri Olsa 1195688d4dfcSCody P Schafer val = term->val.num; 119699e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1197688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1198bb963e16SNamhyung Kim if (verbose > 0) { 1199688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1200688d4dfcSCody P Schafer term->config, term->val.str); 1201e64b020bSJiri Olsa } 1202e64b020bSJiri Olsa if (err) { 12036c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1204448d732cSIan Rogers strdup("expected numeric value"), 1205448d732cSIan Rogers NULL); 1206e64b020bSJiri Olsa } 1207688d4dfcSCody P Schafer return -EINVAL; 1208688d4dfcSCody P Schafer } 1209688d4dfcSCody P Schafer 1210688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1211688d4dfcSCody P Schafer return -EINVAL; 1212688d4dfcSCody P Schafer } else 1213688d4dfcSCody P Schafer return -EINVAL; 1214688d4dfcSCody P Schafer 12150efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 12160efe6b67SAdrian Hunter if (val > max_val) { 12170efe6b67SAdrian Hunter if (err) { 1218448d732cSIan Rogers char *err_str; 1219448d732cSIan Rogers 12206c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1221448d732cSIan Rogers asprintf(&err_str, 12220efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1223448d732cSIan Rogers (unsigned long long)max_val) < 0 1224448d732cSIan Rogers ? strdup("value too big for format") 1225448d732cSIan Rogers : err_str, 1226448d732cSIan Rogers NULL); 12270efe6b67SAdrian Hunter return -EINVAL; 12280efe6b67SAdrian Hunter } 12290efe6b67SAdrian Hunter /* 12300efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 12310efe6b67SAdrian Hunter * silently truncated. 12320efe6b67SAdrian Hunter */ 12330efe6b67SAdrian Hunter } 12340efe6b67SAdrian Hunter 1235688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1236cd82a32eSJiri Olsa return 0; 1237cd82a32eSJiri Olsa } 1238cd82a32eSJiri Olsa 12394ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1240cff7f956SJiri Olsa struct perf_event_attr *attr, 1241dc0a6202SAdrian Hunter struct list_head *head_terms, 1242e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1243cd82a32eSJiri Olsa { 12446cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1245cd82a32eSJiri Olsa 1246688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 12474ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1248e64b020bSJiri Olsa zero, err)) 1249cd82a32eSJiri Olsa return -EINVAL; 1250688d4dfcSCody P Schafer } 1251cd82a32eSJiri Olsa 1252cd82a32eSJiri Olsa return 0; 1253cd82a32eSJiri Olsa } 1254cd82a32eSJiri Olsa 1255cd82a32eSJiri Olsa /* 1256cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1257cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1258cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1259cd82a32eSJiri Olsa */ 1260cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1261e64b020bSJiri Olsa struct list_head *head_terms, 1262e64b020bSJiri Olsa struct parse_events_error *err) 1263cd82a32eSJiri Olsa { 1264dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1265dc0a6202SAdrian Hunter 12664ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 12674ac22b48SIan Rogers head_terms, zero, err); 1268cd82a32eSJiri Olsa } 1269cd82a32eSJiri Olsa 12705c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 12716cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1272a6146d50SZheng Yan { 12735c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1274a6146d50SZheng Yan char *name; 1275a6146d50SZheng Yan 1276a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1277a6146d50SZheng Yan return NULL; 1278a6146d50SZheng Yan 1279a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1280a6146d50SZheng Yan if (term->val.num != 1) 1281a6146d50SZheng Yan return NULL; 1282a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1283a6146d50SZheng Yan return NULL; 1284a6146d50SZheng Yan name = term->config; 1285a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1286a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1287a6146d50SZheng Yan return NULL; 1288a6146d50SZheng Yan name = term->val.str; 1289a6146d50SZheng Yan } else { 1290a6146d50SZheng Yan return NULL; 1291a6146d50SZheng Yan } 1292a6146d50SZheng Yan 1293a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1294a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1295a6146d50SZheng Yan return alias; 1296a6146d50SZheng Yan } 1297a6146d50SZheng Yan return NULL; 1298a6146d50SZheng Yan } 1299a6146d50SZheng Yan 1300410136f5SStephane Eranian 13011d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 13021d9e446bSJiri Olsa struct perf_pmu_info *info) 1303410136f5SStephane Eranian { 1304410136f5SStephane Eranian /* 1305410136f5SStephane Eranian * Only one term in event definition can 13061d9e446bSJiri Olsa * define unit, scale and snapshot, fail 13071d9e446bSJiri Olsa * if there's more than one. 1308410136f5SStephane Eranian */ 1309b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 13101d9e446bSJiri Olsa (info->scale && alias->scale) || 13111d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1312410136f5SStephane Eranian return -EINVAL; 1313410136f5SStephane Eranian 1314b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 13151d9e446bSJiri Olsa info->unit = alias->unit; 1316410136f5SStephane Eranian 1317410136f5SStephane Eranian if (alias->scale) 13181d9e446bSJiri Olsa info->scale = alias->scale; 13191d9e446bSJiri Olsa 13201d9e446bSJiri Olsa if (alias->snapshot) 13211d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1322410136f5SStephane Eranian 1323410136f5SStephane Eranian return 0; 1324410136f5SStephane Eranian } 1325410136f5SStephane Eranian 1326a6146d50SZheng Yan /* 1327a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1328a6146d50SZheng Yan * defined for the alias 1329a6146d50SZheng Yan */ 1330410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 133146441bdcSMatt Fleming struct perf_pmu_info *info) 1332a6146d50SZheng Yan { 13336cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 13345c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1335a6146d50SZheng Yan int ret; 1336a6146d50SZheng Yan 1337044330c1SMatt Fleming info->per_pkg = false; 1338044330c1SMatt Fleming 13398a398897SStephane Eranian /* 13408a398897SStephane Eranian * Mark unit and scale as not set 13418a398897SStephane Eranian * (different from default values, see below) 13428a398897SStephane Eranian */ 134346441bdcSMatt Fleming info->unit = NULL; 134446441bdcSMatt Fleming info->scale = 0.0; 13451d9e446bSJiri Olsa info->snapshot = false; 1346410136f5SStephane Eranian 1347a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1348a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1349a6146d50SZheng Yan if (!alias) 1350a6146d50SZheng Yan continue; 1351a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1352a6146d50SZheng Yan if (ret) 1353a6146d50SZheng Yan return ret; 1354410136f5SStephane Eranian 13551d9e446bSJiri Olsa ret = check_info_data(alias, info); 1356410136f5SStephane Eranian if (ret) 1357410136f5SStephane Eranian return ret; 1358410136f5SStephane Eranian 1359044330c1SMatt Fleming if (alias->per_pkg) 1360044330c1SMatt Fleming info->per_pkg = true; 1361044330c1SMatt Fleming 1362e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 13631dc92556SIan Rogers parse_events_term__delete(term); 1364a6146d50SZheng Yan } 13658a398897SStephane Eranian 13668a398897SStephane Eranian /* 13678a398897SStephane Eranian * if no unit or scale found in aliases, then 13688a398897SStephane Eranian * set defaults as for evsel 13698a398897SStephane Eranian * unit cannot left to NULL 13708a398897SStephane Eranian */ 137146441bdcSMatt Fleming if (info->unit == NULL) 137246441bdcSMatt Fleming info->unit = ""; 13738a398897SStephane Eranian 137446441bdcSMatt Fleming if (info->scale == 0.0) 137546441bdcSMatt Fleming info->scale = 1.0; 13768a398897SStephane Eranian 1377a6146d50SZheng Yan return 0; 1378a6146d50SZheng Yan } 1379a6146d50SZheng Yan 1380cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1381cd82a32eSJiri Olsa int config, unsigned long *bits) 1382cd82a32eSJiri Olsa { 13835c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1384cd82a32eSJiri Olsa 1385cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1386cd82a32eSJiri Olsa if (!format) 1387cd82a32eSJiri Olsa return -ENOMEM; 1388cd82a32eSJiri Olsa 1389cd82a32eSJiri Olsa format->name = strdup(name); 1390cd82a32eSJiri Olsa format->value = config; 1391cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1392cd82a32eSJiri Olsa 1393cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1394cd82a32eSJiri Olsa return 0; 1395cd82a32eSJiri Olsa } 1396cd82a32eSJiri Olsa 1397cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1398cd82a32eSJiri Olsa { 1399cd82a32eSJiri Olsa long b; 1400cd82a32eSJiri Olsa 1401cd82a32eSJiri Olsa if (!to) 1402cd82a32eSJiri Olsa to = from; 1403cd82a32eSJiri Olsa 140415268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1405cd82a32eSJiri Olsa for (b = from; b <= to; b++) 140649bd97c2SSean Christopherson __set_bit(b, bits); 1407cd82a32eSJiri Olsa } 1408dc098b35SAndi Kleen 1409d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1410d26383dcSNamhyung Kim { 1411d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1412d26383dcSNamhyung Kim 1413d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1414d26383dcSNamhyung Kim list_del(&fmt->list); 1415efe98a7aSArnaldo Carvalho de Melo zfree(&fmt->name); 1416d26383dcSNamhyung Kim free(fmt); 1417d26383dcSNamhyung Kim } 1418d26383dcSNamhyung Kim } 1419d26383dcSNamhyung Kim 1420d504fae9SJohn Garry bool is_pmu_core(const char *name) 1421d504fae9SJohn Garry { 14224bf7e81aSIan Rogers return !strcmp(name, "cpu") || is_sysfs_pmu_core(name); 14234bf7e81aSIan Rogers } 14244bf7e81aSIan Rogers 14256fd1e519SIan Rogers bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu) 14266fd1e519SIan Rogers { 1427e20d1f2fSIan Rogers return pmu->is_core; 14286fd1e519SIan Rogers } 14296fd1e519SIan Rogers 143052c7b4d3SIan Rogers bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu) 143152c7b4d3SIan Rogers { 1432e2342142SIan Rogers return pmu->is_core && perf_pmus__num_core_pmus() == 1; 143352c7b4d3SIan Rogers } 143452c7b4d3SIan Rogers 14351eaf496eSIan Rogers bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name) 1436abe9544eSIan Rogers { 14374cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 14384cabc3d1SAndi Kleen 14391eaf496eSIan Rogers list_for_each_entry(alias, &pmu->aliases, list) { 14404cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 14414cabc3d1SAndi Kleen return true; 14424cabc3d1SAndi Kleen } 14434cabc3d1SAndi Kleen return false; 14444cabc3d1SAndi Kleen } 14457d4bdab5SAdrian Hunter 1446251aa040SIan Rogers bool perf_pmu__is_software(const struct perf_pmu *pmu) 1447251aa040SIan Rogers { 1448251aa040SIan Rogers if (pmu->is_core || pmu->is_uncore || pmu->auxtrace) 1449251aa040SIan Rogers return false; 1450251aa040SIan Rogers switch (pmu->type) { 1451251aa040SIan Rogers case PERF_TYPE_HARDWARE: return false; 1452251aa040SIan Rogers case PERF_TYPE_SOFTWARE: return true; 1453251aa040SIan Rogers case PERF_TYPE_TRACEPOINT: return true; 1454251aa040SIan Rogers case PERF_TYPE_HW_CACHE: return false; 1455251aa040SIan Rogers case PERF_TYPE_RAW: return false; 1456251aa040SIan Rogers case PERF_TYPE_BREAKPOINT: return true; 1457251aa040SIan Rogers default: break; 1458251aa040SIan Rogers } 1459251aa040SIan Rogers return !strcmp(pmu->name, "kprobe") || !strcmp(pmu->name, "uprobe"); 1460251aa040SIan Rogers } 1461251aa040SIan Rogers 1462d50a79cdSJames Clark FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 14637d4bdab5SAdrian Hunter { 14647d4bdab5SAdrian Hunter char path[PATH_MAX]; 14657d4bdab5SAdrian Hunter 1466f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name) || 1467f8ad6018SJames Clark !file_available(path)) 14687d4bdab5SAdrian Hunter return NULL; 14697d4bdab5SAdrian Hunter 14707d4bdab5SAdrian Hunter return fopen(path, "r"); 14717d4bdab5SAdrian Hunter } 14727d4bdab5SAdrian Hunter 14733a69672eSNamhyung Kim FILE *perf_pmu__open_file_at(struct perf_pmu *pmu, int dirfd, const char *name) 14743a69672eSNamhyung Kim { 14753a69672eSNamhyung Kim int fd; 14763a69672eSNamhyung Kim 14773a69672eSNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, pmu->name, name, O_RDONLY); 14783a69672eSNamhyung Kim if (fd < 0) 14793a69672eSNamhyung Kim return NULL; 14803a69672eSNamhyung Kim 14813a69672eSNamhyung Kim return fdopen(fd, "r"); 14823a69672eSNamhyung Kim } 14833a69672eSNamhyung Kim 14847d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 14857d4bdab5SAdrian Hunter ...) 14867d4bdab5SAdrian Hunter { 14877d4bdab5SAdrian Hunter va_list args; 14887d4bdab5SAdrian Hunter FILE *file; 14897d4bdab5SAdrian Hunter int ret = EOF; 14907d4bdab5SAdrian Hunter 14917d4bdab5SAdrian Hunter va_start(args, fmt); 14927d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 14937d4bdab5SAdrian Hunter if (file) { 14947d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 14957d4bdab5SAdrian Hunter fclose(file); 14967d4bdab5SAdrian Hunter } 14977d4bdab5SAdrian Hunter va_end(args); 14987d4bdab5SAdrian Hunter return ret; 14997d4bdab5SAdrian Hunter } 15009fbc61f8SKan Liang 15013a69672eSNamhyung Kim int perf_pmu__scan_file_at(struct perf_pmu *pmu, int dirfd, const char *name, 15023a69672eSNamhyung Kim const char *fmt, ...) 15033a69672eSNamhyung Kim { 15043a69672eSNamhyung Kim va_list args; 15053a69672eSNamhyung Kim FILE *file; 15063a69672eSNamhyung Kim int ret = EOF; 15073a69672eSNamhyung Kim 15083a69672eSNamhyung Kim va_start(args, fmt); 15093a69672eSNamhyung Kim file = perf_pmu__open_file_at(pmu, dirfd, name); 15103a69672eSNamhyung Kim if (file) { 15113a69672eSNamhyung Kim ret = vfscanf(file, fmt, args); 15123a69672eSNamhyung Kim fclose(file); 15133a69672eSNamhyung Kim } 15143a69672eSNamhyung Kim va_end(args); 15153a69672eSNamhyung Kim return ret; 15163a69672eSNamhyung Kim } 15173a69672eSNamhyung Kim 1518c2b6a896SGerman Gomez bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name) 1519c2b6a896SGerman Gomez { 1520c2b6a896SGerman Gomez char path[PATH_MAX]; 1521c2b6a896SGerman Gomez 1522c2b6a896SGerman Gomez if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name)) 1523c2b6a896SGerman Gomez return false; 1524c2b6a896SGerman Gomez 1525c2b6a896SGerman Gomez return file_available(path); 1526c2b6a896SGerman Gomez } 1527c2b6a896SGerman Gomez 15289fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 15299fbc61f8SKan Liang { 15309fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 15319fbc61f8SKan Liang 15329fbc61f8SKan Liang if (!caps) 15339fbc61f8SKan Liang return -ENOMEM; 15349fbc61f8SKan Liang 15359fbc61f8SKan Liang caps->name = strdup(name); 15369fbc61f8SKan Liang if (!caps->name) 15379fbc61f8SKan Liang goto free_caps; 15389fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 15399fbc61f8SKan Liang if (!caps->value) 15409fbc61f8SKan Liang goto free_name; 15419fbc61f8SKan Liang list_add_tail(&caps->list, list); 15429fbc61f8SKan Liang return 0; 15439fbc61f8SKan Liang 15449fbc61f8SKan Liang free_name: 154557f14b5aSArnaldo Carvalho de Melo zfree(&caps->name); 15469fbc61f8SKan Liang free_caps: 15479fbc61f8SKan Liang free(caps); 15489fbc61f8SKan Liang 15499fbc61f8SKan Liang return -ENOMEM; 15509fbc61f8SKan Liang } 15519fbc61f8SKan Liang 1552eec11310SNamhyung Kim static void perf_pmu__del_caps(struct perf_pmu *pmu) 1553eec11310SNamhyung Kim { 1554eec11310SNamhyung Kim struct perf_pmu_caps *caps, *tmp; 1555eec11310SNamhyung Kim 1556eec11310SNamhyung Kim list_for_each_entry_safe(caps, tmp, &pmu->caps, list) { 1557eec11310SNamhyung Kim list_del(&caps->list); 1558efe98a7aSArnaldo Carvalho de Melo zfree(&caps->name); 1559efe98a7aSArnaldo Carvalho de Melo zfree(&caps->value); 1560eec11310SNamhyung Kim free(caps); 1561eec11310SNamhyung Kim } 1562eec11310SNamhyung Kim } 1563eec11310SNamhyung Kim 15649fbc61f8SKan Liang /* 15659fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 15669fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 15679fbc61f8SKan Liang * Return the number of capabilities 15689fbc61f8SKan Liang */ 15699fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 15709fbc61f8SKan Liang { 15719fbc61f8SKan Liang struct stat st; 15729fbc61f8SKan Liang char caps_path[PATH_MAX]; 15739fbc61f8SKan Liang DIR *caps_dir; 15749fbc61f8SKan Liang struct dirent *evt_ent; 1575b39094d3SNamhyung Kim int caps_fd; 15763339ec44SRavi Bangoria 15773339ec44SRavi Bangoria if (pmu->caps_initialized) 15783339ec44SRavi Bangoria return pmu->nr_caps; 15793339ec44SRavi Bangoria 15803339ec44SRavi Bangoria pmu->nr_caps = 0; 15819fbc61f8SKan Liang 1582f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name, "caps")) 15839fbc61f8SKan Liang return -1; 15849fbc61f8SKan Liang 15853339ec44SRavi Bangoria if (stat(caps_path, &st) < 0) { 15863339ec44SRavi Bangoria pmu->caps_initialized = true; 15879fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 15883339ec44SRavi Bangoria } 15899fbc61f8SKan Liang 15909fbc61f8SKan Liang caps_dir = opendir(caps_path); 15919fbc61f8SKan Liang if (!caps_dir) 15929fbc61f8SKan Liang return -EINVAL; 15939fbc61f8SKan Liang 1594b39094d3SNamhyung Kim caps_fd = dirfd(caps_dir); 1595b39094d3SNamhyung Kim 15969fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 15979fbc61f8SKan Liang char *name = evt_ent->d_name; 15989fbc61f8SKan Liang char value[128]; 15999fbc61f8SKan Liang FILE *file; 1600b39094d3SNamhyung Kim int fd; 16019fbc61f8SKan Liang 16029fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 16039fbc61f8SKan Liang continue; 16049fbc61f8SKan Liang 1605b39094d3SNamhyung Kim fd = openat(caps_fd, name, O_RDONLY); 16060ea8920eSIan Rogers if (fd == -1) 16079fbc61f8SKan Liang continue; 16080ea8920eSIan Rogers file = fdopen(fd, "r"); 16090ea8920eSIan Rogers if (!file) { 16100ea8920eSIan Rogers close(fd); 16110ea8920eSIan Rogers continue; 16120ea8920eSIan Rogers } 16139fbc61f8SKan Liang 16149fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 16159fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 16169fbc61f8SKan Liang fclose(file); 16179fbc61f8SKan Liang continue; 16189fbc61f8SKan Liang } 16199fbc61f8SKan Liang 16203339ec44SRavi Bangoria pmu->nr_caps++; 16219fbc61f8SKan Liang fclose(file); 16229fbc61f8SKan Liang } 16239fbc61f8SKan Liang 16249fbc61f8SKan Liang closedir(caps_dir); 16259fbc61f8SKan Liang 16263339ec44SRavi Bangoria pmu->caps_initialized = true; 16273339ec44SRavi Bangoria return pmu->nr_caps; 16289fbc61f8SKan Liang } 1629e4064776SJin Yao 1630e4064776SJin Yao void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 16318e8bbfb3SIan Rogers const char *name) 1632e4064776SJin Yao { 1633e4064776SJin Yao struct perf_pmu_format *format; 1634e4064776SJin Yao __u64 masks = 0, bits; 1635e4064776SJin Yao char buf[100]; 1636e4064776SJin Yao unsigned int i; 1637e4064776SJin Yao 1638e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1639e4064776SJin Yao if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG) 1640e4064776SJin Yao continue; 1641e4064776SJin Yao 1642e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1643e4064776SJin Yao masks |= 1ULL << i; 1644e4064776SJin Yao } 1645e4064776SJin Yao 1646e4064776SJin Yao /* 1647e4064776SJin Yao * Kernel doesn't export any valid format bits. 1648e4064776SJin Yao */ 1649e4064776SJin Yao if (masks == 0) 1650e4064776SJin Yao return; 1651e4064776SJin Yao 1652e4064776SJin Yao bits = config & ~masks; 1653e4064776SJin Yao if (bits == 0) 1654e4064776SJin Yao return; 1655e4064776SJin Yao 1656e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1657e4064776SJin Yao 1658e4064776SJin Yao pr_warning("WARNING: event '%s' not valid (bits %s of config " 1659e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1660e4064776SJin Yao name ?: "N/A", buf, config); 1661e4064776SJin Yao } 1662c5a26ea4SJin Yao 1663c47a5599SJin Yao int perf_pmu__match(char *pattern, char *name, char *tok) 1664c47a5599SJin Yao { 166513d60ba0SKan Liang if (!name) 166613d60ba0SKan Liang return -1; 166713d60ba0SKan Liang 1668c47a5599SJin Yao if (fnmatch(pattern, name, 0)) 1669c47a5599SJin Yao return -1; 1670c47a5599SJin Yao 1671240e6fd0SIan Rogers if (tok && !perf_pmu__match_ignoring_suffix(name, tok)) 1672c47a5599SJin Yao return -1; 1673c47a5599SJin Yao 1674c47a5599SJin Yao return 0; 1675c47a5599SJin Yao } 16761d3351e6SJin Yao 1677acef233bSJing Zhang double __weak perf_pmu__cpu_slots_per_cycle(void) 1678acef233bSJing Zhang { 1679acef233bSJing Zhang return NAN; 1680acef233bSJing Zhang } 1681f8ad6018SJames Clark 1682f8ad6018SJames Clark int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size) 1683f8ad6018SJames Clark { 1684f8ad6018SJames Clark const char *sysfs = sysfs__mountpoint(); 1685f8ad6018SJames Clark 1686f8ad6018SJames Clark if (!sysfs) 1687f8ad6018SJames Clark return 0; 1688f8ad6018SJames Clark return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs); 1689f8ad6018SJames Clark } 1690f8ad6018SJames Clark 1691e293a5e8SNamhyung Kim int perf_pmu__event_source_devices_fd(void) 1692e293a5e8SNamhyung Kim { 1693e293a5e8SNamhyung Kim char path[PATH_MAX]; 1694e293a5e8SNamhyung Kim const char *sysfs = sysfs__mountpoint(); 1695e293a5e8SNamhyung Kim 1696e293a5e8SNamhyung Kim if (!sysfs) 1697e293a5e8SNamhyung Kim return -1; 1698e293a5e8SNamhyung Kim 1699e293a5e8SNamhyung Kim scnprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs); 1700e293a5e8SNamhyung Kim return open(path, O_DIRECTORY); 1701e293a5e8SNamhyung Kim } 1702e293a5e8SNamhyung Kim 1703f8ad6018SJames Clark /* 1704f8ad6018SJames Clark * Fill 'buf' with the path to a file or folder in 'pmu_name' in 1705f8ad6018SJames Clark * sysfs. For example if pmu_name = "cs_etm" and 'filename' = "format" 1706f8ad6018SJames Clark * then pathname will be filled with 1707f8ad6018SJames Clark * "/sys/bus/event_source/devices/cs_etm/format" 1708f8ad6018SJames Clark * 1709f8ad6018SJames Clark * Return 0 if the sysfs mountpoint couldn't be found or if no 1710f8ad6018SJames Clark * characters were written. 1711f8ad6018SJames Clark */ 1712f8ad6018SJames Clark int perf_pmu__pathname_scnprintf(char *buf, size_t size, 1713f8ad6018SJames Clark const char *pmu_name, const char *filename) 1714f8ad6018SJames Clark { 1715f8ad6018SJames Clark char base_path[PATH_MAX]; 1716f8ad6018SJames Clark 1717f8ad6018SJames Clark if (!perf_pmu__event_source_devices_scnprintf(base_path, sizeof(base_path))) 1718f8ad6018SJames Clark return 0; 1719f8ad6018SJames Clark return scnprintf(buf, size, "%s%s/%s", base_path, pmu_name, filename); 1720f8ad6018SJames Clark } 1721eec11310SNamhyung Kim 1722e293a5e8SNamhyung Kim int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags) 1723e293a5e8SNamhyung Kim { 1724e293a5e8SNamhyung Kim char path[PATH_MAX]; 1725e293a5e8SNamhyung Kim 1726e293a5e8SNamhyung Kim scnprintf(path, sizeof(path), "%s/%s", pmu_name, filename); 1727e293a5e8SNamhyung Kim return openat(dirfd, path, flags); 1728e293a5e8SNamhyung Kim } 1729e293a5e8SNamhyung Kim 17301eaf496eSIan Rogers void perf_pmu__delete(struct perf_pmu *pmu) 1731eec11310SNamhyung Kim { 1732eec11310SNamhyung Kim perf_pmu__del_formats(&pmu->format); 1733eec11310SNamhyung Kim perf_pmu__del_aliases(pmu); 1734eec11310SNamhyung Kim perf_pmu__del_caps(pmu); 1735eec11310SNamhyung Kim 1736eec11310SNamhyung Kim perf_cpu_map__put(pmu->cpus); 1737eec11310SNamhyung Kim 1738efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->default_config); 1739efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->name); 1740efe98a7aSArnaldo Carvalho de Melo zfree(&pmu->alias_name); 1741eec11310SNamhyung Kim free(pmu); 1742eec11310SNamhyung Kim } 1743