1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2cd82a32eSJiri Olsa #include <linux/list.h> 3c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 432858480SArnaldo Carvalho de Melo #include <linux/string.h> 57f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 6c47a5599SJin Yao #include <linux/ctype.h> 7fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h> 8cd82a32eSJiri Olsa #include <sys/types.h> 9a43783aeSArnaldo Carvalho de Melo #include <errno.h> 10c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h> 117a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 12cd82a32eSJiri Olsa #include <unistd.h> 13cd82a32eSJiri Olsa #include <stdio.h> 14dc0a6202SAdrian Hunter #include <stdbool.h> 157d4bdab5SAdrian Hunter #include <stdarg.h> 16cd82a32eSJiri Olsa #include <dirent.h> 17cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 18410136f5SStephane Eranian #include <locale.h> 19fbc2844eSWilliam Cohen #include <regex.h> 209c3516d1SJiri Olsa #include <perf/cpumap.h> 21c47a5599SJin Yao #include <fnmatch.h> 22acef233bSJing Zhang #include <math.h> 235e51b0bbSArnaldo Carvalho de Melo #include "debug.h" 24e12ee9f7SAdrian Hunter #include "evsel.h" 25cd82a32eSJiri Olsa #include "pmu.h" 26336b92daSRavi Bangoria #include "pmus.h" 273d88aec0SIan Rogers #include "pmu-bison.h" 283d88aec0SIan Rogers #include "pmu-flex.h" 29cd82a32eSJiri Olsa #include "parse-events.h" 30e5c6109fSIan Rogers #include "print-events.h" 31933f82ffSSukadev Bhattiprolu #include "header.h" 32a067558eSArnaldo Carvalho de Melo #include "string2.h" 33fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h" 34d9664582SAndi Kleen #include "fncache.h" 3544462430SJin Yao #include "pmu-hybrid.h" 36cd82a32eSJiri Olsa 37e46fc8d9SArnaldo Carvalho de Melo struct perf_pmu perf_pmu__fake; 38e46fc8d9SArnaldo Carvalho de Melo 39fe13d43dSIan Rogers /** 40fe13d43dSIan Rogers * struct perf_pmu_format - Values from a format file read from 41fe13d43dSIan Rogers * <sysfs>/devices/cpu/format/ held in struct perf_pmu. 42fe13d43dSIan Rogers * 43fe13d43dSIan Rogers * For example, the contents of <sysfs>/devices/cpu/format/event may be 44fe13d43dSIan Rogers * "config:0-7" and will be represented here as name="event", 45fe13d43dSIan Rogers * value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set. 46fe13d43dSIan Rogers */ 47ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 48fe13d43dSIan Rogers /** @name: The modifier/file name. */ 49ab1bf653SArnaldo Carvalho de Melo char *name; 50fe13d43dSIan Rogers /** 51fe13d43dSIan Rogers * @value : Which config value the format relates to. Supported values 52fe13d43dSIan Rogers * are from PERF_PMU_FORMAT_VALUE_CONFIG to 53fe13d43dSIan Rogers * PERF_PMU_FORMAT_VALUE_CONFIG_END. 54fe13d43dSIan Rogers */ 55ab1bf653SArnaldo Carvalho de Melo int value; 56fe13d43dSIan Rogers /** @bits: Which config bits are set by this format value. */ 57ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 58fe13d43dSIan Rogers /** @list: Element on list within struct perf_pmu. */ 59ab1bf653SArnaldo Carvalho de Melo struct list_head list; 60ab1bf653SArnaldo Carvalho de Melo }; 61ab1bf653SArnaldo Carvalho de Melo 62c5a26ea4SJin Yao static bool hybrid_scanned; 63cd82a32eSJiri Olsa 64e293a5e8SNamhyung Kim static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name); 65e293a5e8SNamhyung Kim 66cd82a32eSJiri Olsa /* 67cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 68cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 69cd82a32eSJiri Olsa */ 70e293a5e8SNamhyung Kim int perf_pmu__format_parse(int dirfd, struct list_head *head) 71cd82a32eSJiri Olsa { 72cd82a32eSJiri Olsa struct dirent *evt_ent; 73cd82a32eSJiri Olsa DIR *format_dir; 74cd82a32eSJiri Olsa int ret = 0; 75cd82a32eSJiri Olsa 76e293a5e8SNamhyung Kim format_dir = fdopendir(dirfd); 77cd82a32eSJiri Olsa if (!format_dir) 78cd82a32eSJiri Olsa return -EINVAL; 79cd82a32eSJiri Olsa 80cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 81cd82a32eSJiri Olsa char *name = evt_ent->d_name; 82e293a5e8SNamhyung Kim int fd; 833d88aec0SIan Rogers void *scanner; 843d88aec0SIan Rogers FILE *file; 85cd82a32eSJiri Olsa 86cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 87cd82a32eSJiri Olsa continue; 88cd82a32eSJiri Olsa 89cd82a32eSJiri Olsa 90cd82a32eSJiri Olsa ret = -EINVAL; 91e293a5e8SNamhyung Kim fd = openat(dirfd, name, O_RDONLY); 92e293a5e8SNamhyung Kim if (fd < 0) 93cd82a32eSJiri Olsa break; 94cd82a32eSJiri Olsa 953d88aec0SIan Rogers file = fdopen(fd, "r"); 963d88aec0SIan Rogers if (!file) { 973d88aec0SIan Rogers close(fd); 983d88aec0SIan Rogers break; 993d88aec0SIan Rogers } 1003d88aec0SIan Rogers 1013d88aec0SIan Rogers ret = perf_pmu_lex_init(&scanner); 1023d88aec0SIan Rogers if (ret) { 1033d88aec0SIan Rogers fclose(file); 1043d88aec0SIan Rogers break; 1053d88aec0SIan Rogers } 1063d88aec0SIan Rogers 1073d88aec0SIan Rogers perf_pmu_set_in(file, scanner); 1083d88aec0SIan Rogers ret = perf_pmu_parse(head, name, scanner); 1093d88aec0SIan Rogers perf_pmu_lex_destroy(scanner); 1103d88aec0SIan Rogers fclose(file); 111cd82a32eSJiri Olsa } 112cd82a32eSJiri Olsa 113cd82a32eSJiri Olsa closedir(format_dir); 114cd82a32eSJiri Olsa return ret; 115cd82a32eSJiri Olsa } 116cd82a32eSJiri Olsa 117cd82a32eSJiri Olsa /* 118cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 119cd82a32eSJiri Olsa * located at: 120cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 121cd82a32eSJiri Olsa */ 122e293a5e8SNamhyung Kim static int pmu_format(int dirfd, const char *name, struct list_head *format) 123cd82a32eSJiri Olsa { 124e293a5e8SNamhyung Kim int fd; 125cd82a32eSJiri Olsa 126e293a5e8SNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "format", O_DIRECTORY); 127e293a5e8SNamhyung Kim if (fd < 0) 128d9664582SAndi Kleen return 0; 129cd82a32eSJiri Olsa 130e293a5e8SNamhyung Kim /* it'll close the fd */ 131e293a5e8SNamhyung Kim if (perf_pmu__format_parse(fd, format)) 132cd82a32eSJiri Olsa return -1; 133cd82a32eSJiri Olsa 134cd82a32eSJiri Olsa return 0; 135cd82a32eSJiri Olsa } 136cd82a32eSJiri Olsa 137a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 138d02fc6bcSAndi Kleen { 139d02fc6bcSAndi Kleen char *lc; 140d02fc6bcSAndi Kleen int ret = 0; 141d02fc6bcSAndi Kleen 142d02fc6bcSAndi Kleen /* 143d02fc6bcSAndi Kleen * save current locale 144d02fc6bcSAndi Kleen */ 145d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 146d02fc6bcSAndi Kleen 147d02fc6bcSAndi Kleen /* 148d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 149d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 150d02fc6bcSAndi Kleen * call below. 151d02fc6bcSAndi Kleen */ 152d02fc6bcSAndi Kleen lc = strdup(lc); 153d02fc6bcSAndi Kleen if (!lc) { 154d02fc6bcSAndi Kleen ret = -ENOMEM; 155d02fc6bcSAndi Kleen goto out; 156d02fc6bcSAndi Kleen } 157d02fc6bcSAndi Kleen 158d02fc6bcSAndi Kleen /* 159d02fc6bcSAndi Kleen * force to C locale to ensure kernel 160d02fc6bcSAndi Kleen * scale string is converted correctly. 161d02fc6bcSAndi Kleen * kernel uses default C locale. 162d02fc6bcSAndi Kleen */ 163d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 164d02fc6bcSAndi Kleen 165d02fc6bcSAndi Kleen *sval = strtod(scale, end); 166d02fc6bcSAndi Kleen 167d02fc6bcSAndi Kleen out: 168d02fc6bcSAndi Kleen /* restore locale */ 169d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 170d02fc6bcSAndi Kleen free(lc); 171d02fc6bcSAndi Kleen return ret; 172d02fc6bcSAndi Kleen } 173d02fc6bcSAndi Kleen 174e293a5e8SNamhyung Kim static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, int dirfd, char *name) 175410136f5SStephane Eranian { 176410136f5SStephane Eranian struct stat st; 177410136f5SStephane Eranian ssize_t sret; 178410136f5SStephane Eranian char scale[128]; 179410136f5SStephane Eranian int fd, ret = -1; 180410136f5SStephane Eranian char path[PATH_MAX]; 181410136f5SStephane Eranian 182e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.scale", name); 183410136f5SStephane Eranian 184e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 185410136f5SStephane Eranian if (fd == -1) 186410136f5SStephane Eranian return -1; 187410136f5SStephane Eranian 188410136f5SStephane Eranian if (fstat(fd, &st) < 0) 189410136f5SStephane Eranian goto error; 190410136f5SStephane Eranian 191410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 192410136f5SStephane Eranian if (sret < 0) 193410136f5SStephane Eranian goto error; 194410136f5SStephane Eranian 1959ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1969ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1979ecae065SMadhavan Srinivasan else 198410136f5SStephane Eranian scale[sret] = '\0'; 1999ecae065SMadhavan Srinivasan 200a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 201410136f5SStephane Eranian error: 202410136f5SStephane Eranian close(fd); 203410136f5SStephane Eranian return ret; 204410136f5SStephane Eranian } 205410136f5SStephane Eranian 206e293a5e8SNamhyung Kim static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, int dirfd, char *name) 207410136f5SStephane Eranian { 208410136f5SStephane Eranian char path[PATH_MAX]; 209410136f5SStephane Eranian ssize_t sret; 210410136f5SStephane Eranian int fd; 211410136f5SStephane Eranian 212e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.unit", name); 213410136f5SStephane Eranian 214e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 215410136f5SStephane Eranian if (fd == -1) 216410136f5SStephane Eranian return -1; 217410136f5SStephane Eranian 218410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 219410136f5SStephane Eranian if (sret < 0) 220410136f5SStephane Eranian goto error; 221410136f5SStephane Eranian 222410136f5SStephane Eranian close(fd); 223410136f5SStephane Eranian 2249ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 2259ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 2269ecae065SMadhavan Srinivasan else 227410136f5SStephane Eranian alias->unit[sret] = '\0'; 228410136f5SStephane Eranian 229410136f5SStephane Eranian return 0; 230410136f5SStephane Eranian error: 231410136f5SStephane Eranian close(fd); 232410136f5SStephane Eranian alias->unit[0] = '\0'; 233410136f5SStephane Eranian return -1; 234410136f5SStephane Eranian } 235410136f5SStephane Eranian 236044330c1SMatt Fleming static int 237e293a5e8SNamhyung Kim perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, int dirfd, char *name) 238044330c1SMatt Fleming { 239044330c1SMatt Fleming char path[PATH_MAX]; 240044330c1SMatt Fleming int fd; 241044330c1SMatt Fleming 242e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.per-pkg", name); 243044330c1SMatt Fleming 244e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 245044330c1SMatt Fleming if (fd == -1) 246044330c1SMatt Fleming return -1; 247044330c1SMatt Fleming 248044330c1SMatt Fleming close(fd); 249044330c1SMatt Fleming 250044330c1SMatt Fleming alias->per_pkg = true; 251044330c1SMatt Fleming return 0; 252044330c1SMatt Fleming } 253044330c1SMatt Fleming 2541d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 255e293a5e8SNamhyung Kim int dirfd, char *name) 2561d9e446bSJiri Olsa { 2571d9e446bSJiri Olsa char path[PATH_MAX]; 2581d9e446bSJiri Olsa int fd; 2591d9e446bSJiri Olsa 260e293a5e8SNamhyung Kim scnprintf(path, PATH_MAX, "%s.snapshot", name); 2611d9e446bSJiri Olsa 262e293a5e8SNamhyung Kim fd = openat(dirfd, path, O_RDONLY); 2631d9e446bSJiri Olsa if (fd == -1) 2641d9e446bSJiri Olsa return -1; 2651d9e446bSJiri Olsa 2661d9e446bSJiri Olsa alias->snapshot = true; 2671d9e446bSJiri Olsa close(fd); 2681d9e446bSJiri Olsa return 0; 2691d9e446bSJiri Olsa } 2701d9e446bSJiri Olsa 2716dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2726dde6429SThomas Richter char **new_str) 2736dde6429SThomas Richter { 2746dde6429SThomas Richter if (!*old_str) 2756dde6429SThomas Richter goto set_new; 2766dde6429SThomas Richter 2776dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2786dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2796dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2806dde6429SThomas Richter name, field); 2816dde6429SThomas Richter zfree(old_str); 2826dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2836dde6429SThomas Richter return; 2846dde6429SThomas Richter set_new: 2856dde6429SThomas Richter *old_str = *new_str; 2866dde6429SThomas Richter *new_str = NULL; 2876dde6429SThomas Richter } 2886dde6429SThomas Richter 2896dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2906dde6429SThomas Richter struct perf_pmu_alias *newalias) 2916dde6429SThomas Richter { 2926dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2936dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2946dde6429SThomas Richter &newalias->long_desc); 2956dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2966dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2976dde6429SThomas Richter old->scale = newalias->scale; 2986dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2996dde6429SThomas Richter old->snapshot = newalias->snapshot; 3006dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 3016dde6429SThomas Richter } 3026dde6429SThomas Richter 3036dde6429SThomas Richter /* Delete an alias entry. */ 30422fe5a25SNamhyung Kim void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 3056dde6429SThomas Richter { 3066dde6429SThomas Richter zfree(&newalias->name); 3076dde6429SThomas Richter zfree(&newalias->desc); 3086dde6429SThomas Richter zfree(&newalias->long_desc); 3096dde6429SThomas Richter zfree(&newalias->topic); 3106dde6429SThomas Richter zfree(&newalias->str); 31132705de7SJin Yao zfree(&newalias->pmu_name); 3126dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 3136dde6429SThomas Richter free(newalias); 3146dde6429SThomas Richter } 3156dde6429SThomas Richter 316eec11310SNamhyung Kim static void perf_pmu__del_aliases(struct perf_pmu *pmu) 317eec11310SNamhyung Kim { 318eec11310SNamhyung Kim struct perf_pmu_alias *alias, *tmp; 319eec11310SNamhyung Kim 320eec11310SNamhyung Kim list_for_each_entry_safe(alias, tmp, &pmu->aliases, list) { 321eec11310SNamhyung Kim list_del(&alias->list); 322eec11310SNamhyung Kim perf_pmu_free_alias(alias); 323eec11310SNamhyung Kim } 324eec11310SNamhyung Kim } 325eec11310SNamhyung Kim 3266dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 3276dde6429SThomas Richter * present merge both of them to combine all information. 3286dde6429SThomas Richter */ 3296dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 3306dde6429SThomas Richter struct list_head *alist) 3316dde6429SThomas Richter { 3326dde6429SThomas Richter struct perf_pmu_alias *a; 3336dde6429SThomas Richter 3346dde6429SThomas Richter list_for_each_entry(a, alist, list) { 3356dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 33632705de7SJin Yao if (newalias->pmu_name && a->pmu_name && 33732705de7SJin Yao !strcasecmp(newalias->pmu_name, a->pmu_name)) { 33832705de7SJin Yao continue; 33932705de7SJin Yao } 3406dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 3416dde6429SThomas Richter perf_pmu_free_alias(newalias); 3426dde6429SThomas Richter return true; 3436dde6429SThomas Richter } 3446dde6429SThomas Richter } 3456dde6429SThomas Richter return false; 3466dde6429SThomas Richter } 3476dde6429SThomas Richter 348e293a5e8SNamhyung Kim static int __perf_pmu__new_alias(struct list_head *list, int dirfd, char *name, 34947f572aaSIan Rogers char *desc, char *val, const struct pmu_event *pe) 350a6146d50SZheng Yan { 3510c24d6fbSThomas Richter struct parse_events_term *term; 3525c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 353a6146d50SZheng Yan int ret; 3540c24d6fbSThomas Richter char newval[256]; 355*330f40a0SIan Rogers const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL; 356bd680861SIan Rogers bool deprecated = false, perpkg = false; 357eab35953SJin Yao 358eab35953SJin Yao if (pe) { 359*330f40a0SIan Rogers long_desc = pe->long_desc; 360*330f40a0SIan Rogers topic = pe->topic; 361*330f40a0SIan Rogers unit = pe->unit; 362bd680861SIan Rogers perpkg = pe->perpkg; 3639ed8b7dcSIan Rogers deprecated = pe->deprecated; 364*330f40a0SIan Rogers pmu_name = pe->pmu; 365eab35953SJin Yao } 366a6146d50SZheng Yan 367a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 368a6146d50SZheng Yan if (!alias) 369a6146d50SZheng Yan return -ENOMEM; 370a6146d50SZheng Yan 371a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 372410136f5SStephane Eranian alias->scale = 1.0; 373410136f5SStephane Eranian alias->unit[0] = '\0'; 374bd680861SIan Rogers alias->per_pkg = perpkg; 37584530920SStephane Eranian alias->snapshot = false; 3769ed8b7dcSIan Rogers alias->deprecated = deprecated; 377410136f5SStephane Eranian 37870c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 379a6146d50SZheng Yan if (ret) { 38070c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 381a6146d50SZheng Yan free(alias); 382a6146d50SZheng Yan return ret; 383a6146d50SZheng Yan } 384a6146d50SZheng Yan 3850c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3860c24d6fbSThomas Richter * platforms have terms specified as 3870c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3880c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3890c24d6fbSThomas Richter * 3900c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3910c24d6fbSThomas Richter */ 3920c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3930c24d6fbSThomas Richter ret = 0; 3940c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3950c24d6fbSThomas Richter if (ret) 3960c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3970c24d6fbSThomas Richter ","); 3980c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3990c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 4000c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 4010c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 4020c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 4030c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 4040c24d6fbSThomas Richter } 4050c24d6fbSThomas Richter 406a6146d50SZheng Yan alias->name = strdup(name); 407e293a5e8SNamhyung Kim if (dirfd >= 0) { 408410136f5SStephane Eranian /* 409410136f5SStephane Eranian * load unit name and scale if available 410410136f5SStephane Eranian */ 411e293a5e8SNamhyung Kim perf_pmu__parse_unit(alias, dirfd, name); 412e293a5e8SNamhyung Kim perf_pmu__parse_scale(alias, dirfd, name); 413e293a5e8SNamhyung Kim perf_pmu__parse_per_pkg(alias, dirfd, name); 414e293a5e8SNamhyung Kim perf_pmu__parse_snapshot(alias, dirfd, name); 41570c646e0SSukadev Bhattiprolu } 416410136f5SStephane Eranian 41708e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 418c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 419c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 420dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 421fedb2b51SAndi Kleen if (unit) { 422*330f40a0SIan Rogers if (perf_pmu__convert_scale(unit, (char **)&unit, &alias->scale) < 0) 423fedb2b51SAndi Kleen return -1; 424fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 425fedb2b51SAndi Kleen } 4260c24d6fbSThomas Richter alias->str = strdup(newval); 42732705de7SJin Yao alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; 428f2361024SAndi Kleen 4296dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 430a6146d50SZheng Yan list_add_tail(&alias->list, list); 431410136f5SStephane Eranian 432a6146d50SZheng Yan return 0; 433a6146d50SZheng Yan } 434a6146d50SZheng Yan 435e293a5e8SNamhyung Kim static int perf_pmu__new_alias(struct list_head *list, int dirfd, char *name, FILE *file) 43670c646e0SSukadev Bhattiprolu { 43770c646e0SSukadev Bhattiprolu char buf[256]; 43870c646e0SSukadev Bhattiprolu int ret; 43970c646e0SSukadev Bhattiprolu 44070c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 44170c646e0SSukadev Bhattiprolu if (ret == 0) 44270c646e0SSukadev Bhattiprolu return -EINVAL; 44370c646e0SSukadev Bhattiprolu 44470c646e0SSukadev Bhattiprolu buf[ret] = 0; 44570c646e0SSukadev Bhattiprolu 446ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 44713c230abSArnaldo Carvalho de Melo strim(buf); 448ea23ac73SThomas Richter 449e293a5e8SNamhyung Kim return __perf_pmu__new_alias(list, dirfd, name, NULL, buf, NULL); 45070c646e0SSukadev Bhattiprolu } 45170c646e0SSukadev Bhattiprolu 45246441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 45346441bdcSMatt Fleming { 45446441bdcSMatt Fleming size_t len; 45546441bdcSMatt Fleming 45646441bdcSMatt Fleming len = strlen(name); 45746441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 45846441bdcSMatt Fleming return true; 45946441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 46046441bdcSMatt Fleming return true; 461044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 462044330c1SMatt Fleming return true; 4631d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4641d9e446bSJiri Olsa return true; 46546441bdcSMatt Fleming 46646441bdcSMatt Fleming return false; 46746441bdcSMatt Fleming } 46846441bdcSMatt Fleming 469a6146d50SZheng Yan /* 470a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 471a6146d50SZheng Yan * specified in 'dir' parameter. 472a6146d50SZheng Yan */ 473e293a5e8SNamhyung Kim static int pmu_aliases_parse(int dirfd, struct list_head *head) 474a6146d50SZheng Yan { 475a6146d50SZheng Yan struct dirent *evt_ent; 476a6146d50SZheng Yan DIR *event_dir; 477e293a5e8SNamhyung Kim int fd; 478a6146d50SZheng Yan 479e293a5e8SNamhyung Kim event_dir = fdopendir(dirfd); 480a6146d50SZheng Yan if (!event_dir) 481a6146d50SZheng Yan return -EINVAL; 482a6146d50SZheng Yan 483940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 484a6146d50SZheng Yan char *name = evt_ent->d_name; 485a6146d50SZheng Yan FILE *file; 486a6146d50SZheng Yan 487a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 488a6146d50SZheng Yan continue; 489a6146d50SZheng Yan 490410136f5SStephane Eranian /* 49146441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 492410136f5SStephane Eranian */ 49346441bdcSMatt Fleming if (pmu_alias_info_file(name)) 494410136f5SStephane Eranian continue; 495410136f5SStephane Eranian 496e293a5e8SNamhyung Kim fd = openat(dirfd, name, O_RDONLY); 4970ea8920eSIan Rogers if (fd == -1) { 4980ea8920eSIan Rogers pr_debug("Cannot open %s\n", name); 4990ea8920eSIan Rogers continue; 5000ea8920eSIan Rogers } 501e293a5e8SNamhyung Kim file = fdopen(fd, "r"); 502940db6dcSAndi Kleen if (!file) { 5030ea8920eSIan Rogers close(fd); 504940db6dcSAndi Kleen continue; 505940db6dcSAndi Kleen } 506410136f5SStephane Eranian 507e293a5e8SNamhyung Kim if (perf_pmu__new_alias(head, dirfd, name, file) < 0) 508940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 509a6146d50SZheng Yan fclose(file); 510a6146d50SZheng Yan } 511a6146d50SZheng Yan 512a6146d50SZheng Yan closedir(event_dir); 513940db6dcSAndi Kleen return 0; 514a6146d50SZheng Yan } 515a6146d50SZheng Yan 516a6146d50SZheng Yan /* 517a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 518a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 519a6146d50SZheng Yan */ 520e293a5e8SNamhyung Kim static int pmu_aliases(int dirfd, const char *name, struct list_head *head) 521a6146d50SZheng Yan { 522e293a5e8SNamhyung Kim int fd; 523a6146d50SZheng Yan 524e293a5e8SNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "events", O_DIRECTORY); 525e293a5e8SNamhyung Kim if (fd < 0) 526d9664582SAndi Kleen return 0; 527a6146d50SZheng Yan 528e293a5e8SNamhyung Kim /* it'll close the fd */ 529e293a5e8SNamhyung Kim if (pmu_aliases_parse(fd, head)) 530a6146d50SZheng Yan return -1; 531a6146d50SZheng Yan 532a6146d50SZheng Yan return 0; 533a6146d50SZheng Yan } 534a6146d50SZheng Yan 5355c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 536a6146d50SZheng Yan struct list_head *terms) 537a6146d50SZheng Yan { 5387c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 539a6146d50SZheng Yan LIST_HEAD(list); 540a6146d50SZheng Yan int ret; 541a6146d50SZheng Yan 542a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5437c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 544a6146d50SZheng Yan if (ret) { 545682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 546a6146d50SZheng Yan return ret; 547a6146d50SZheng Yan } 548c2f1ceadSAndi Kleen /* 549c2f1ceadSAndi Kleen * Weak terms don't override command line options, 550c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 551c2f1ceadSAndi Kleen */ 552c2f1ceadSAndi Kleen cloned->weak = true; 5537c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 554a6146d50SZheng Yan } 555a6146d50SZheng Yan list_splice(&list, terms); 556a6146d50SZheng Yan return 0; 557a6146d50SZheng Yan } 558a6146d50SZheng Yan 55950a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 56050a9667cSRobert Richter static void pmu_read_sysfs(void) 56150a9667cSRobert Richter { 562e293a5e8SNamhyung Kim int fd; 56350a9667cSRobert Richter DIR *dir; 56450a9667cSRobert Richter struct dirent *dent; 56550a9667cSRobert Richter 566e293a5e8SNamhyung Kim fd = perf_pmu__event_source_devices_fd(); 567e293a5e8SNamhyung Kim if (fd < 0) 56850a9667cSRobert Richter return; 56950a9667cSRobert Richter 570e293a5e8SNamhyung Kim dir = fdopendir(fd); 57150a9667cSRobert Richter if (!dir) 57250a9667cSRobert Richter return; 57350a9667cSRobert Richter 57450a9667cSRobert Richter while ((dent = readdir(dir))) { 57550a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 57650a9667cSRobert Richter continue; 57750a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 578e293a5e8SNamhyung Kim perf_pmu__find2(fd, dent->d_name); 57950a9667cSRobert Richter } 58050a9667cSRobert Richter 58150a9667cSRobert Richter closedir(dir); 58250a9667cSRobert Richter } 58350a9667cSRobert Richter 58466ec1191SMark Rutland /* 58566ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 58666ec1191SMark Rutland * may have a "cpus" file. 58766ec1191SMark Rutland */ 5883a69672eSNamhyung Kim static struct perf_cpu_map *pmu_cpumask(int dirfd, const char *name) 5897ae92e74SYan, Zheng { 590f854839bSJiri Olsa struct perf_cpu_map *cpus; 5917e3fcffeSMark Rutland const char *templates[] = { 592d50a79cdSJames Clark "cpumask", 593d50a79cdSJames Clark "cpus", 5947e3fcffeSMark Rutland NULL 5957e3fcffeSMark Rutland }; 5967e3fcffeSMark Rutland const char **template; 597d50a79cdSJames Clark char pmu_name[PATH_MAX]; 598d50a79cdSJames Clark struct perf_pmu pmu = {.name = pmu_name}; 599d50a79cdSJames Clark FILE *file; 6007ae92e74SYan, Zheng 601d50a79cdSJames Clark strlcpy(pmu_name, name, sizeof(pmu_name)); 6027e3fcffeSMark Rutland for (template = templates; *template; template++) { 6033a69672eSNamhyung Kim file = perf_pmu__open_file_at(&pmu, dirfd, *template); 604d50a79cdSJames Clark if (!file) 605d50a79cdSJames Clark continue; 606d50a79cdSJames Clark cpus = perf_cpu_map__read(file); 6073a69672eSNamhyung Kim fclose(file); 60866ec1191SMark Rutland if (cpus) 60966ec1191SMark Rutland return cpus; 6107e3fcffeSMark Rutland } 6117ae92e74SYan, Zheng 6127ae92e74SYan, Zheng return NULL; 61366ec1191SMark Rutland } 6147ae92e74SYan, Zheng 6153a69672eSNamhyung Kim static bool pmu_is_uncore(int dirfd, const char *name) 61666ec1191SMark Rutland { 6173a69672eSNamhyung Kim int fd; 6187ae92e74SYan, Zheng 61944462430SJin Yao if (perf_pmu__hybrid_mounted(name)) 62044462430SJin Yao return false; 62144462430SJin Yao 6223a69672eSNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, name, "cpumask", O_PATH); 6233a69672eSNamhyung Kim if (fd < 0) 6243a69672eSNamhyung Kim return false; 6253a69672eSNamhyung Kim 6263a69672eSNamhyung Kim close(fd); 6273a69672eSNamhyung Kim return true; 6287ae92e74SYan, Zheng } 6297ae92e74SYan, Zheng 63051d54847SJohn Garry static char *pmu_id(const char *name) 63151d54847SJohn Garry { 63251d54847SJohn Garry char path[PATH_MAX], *str; 63351d54847SJohn Garry size_t len; 63451d54847SJohn Garry 6355f2c8efaSJames Clark perf_pmu__pathname_scnprintf(path, sizeof(path), name, "identifier"); 63651d54847SJohn Garry 6375f2c8efaSJames Clark if (filename__read_str(path, &str, &len) < 0) 63851d54847SJohn Garry return NULL; 63951d54847SJohn Garry 64051d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 64151d54847SJohn Garry 64251d54847SJohn Garry return str; 64351d54847SJohn Garry } 64451d54847SJohn Garry 645933f82ffSSukadev Bhattiprolu /* 64614b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 647292c34c1SKan Liang * platforms. 648292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 64914b22ae0SGanapatrao Kulkarni */ 650292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 65114b22ae0SGanapatrao Kulkarni { 65214b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 65314b22ae0SGanapatrao Kulkarni 654f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpus")) 65514b22ae0SGanapatrao Kulkarni return 0; 656d9664582SAndi Kleen return file_available(path); 65714b22ae0SGanapatrao Kulkarni } 65814b22ae0SGanapatrao Kulkarni 65929be2fe0SIan Rogers char *perf_pmu__getcpuid(struct perf_pmu *pmu) 660d77ade9fSAndi Kleen { 661d77ade9fSAndi Kleen char *cpuid; 662d77ade9fSAndi Kleen static bool printed; 663d77ade9fSAndi Kleen 664d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 665d77ade9fSAndi Kleen if (cpuid) 666d77ade9fSAndi Kleen cpuid = strdup(cpuid); 667d77ade9fSAndi Kleen if (!cpuid) 66854e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 669d77ade9fSAndi Kleen if (!cpuid) 670d77ade9fSAndi Kleen return NULL; 671d77ade9fSAndi Kleen 672d77ade9fSAndi Kleen if (!printed) { 673d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 674d77ade9fSAndi Kleen printed = true; 675d77ade9fSAndi Kleen } 676d77ade9fSAndi Kleen return cpuid; 677d77ade9fSAndi Kleen } 678d77ade9fSAndi Kleen 6791ba3752aSIan Rogers __weak const struct pmu_events_table *pmu_events_table__find(void) 680e126bef5SJohn Garry { 68196d2a746SIan Rogers return perf_pmu__find_events_table(NULL); 682e126bef5SJohn Garry } 683e126bef5SJohn Garry 684f8ea2c15SIan Rogers __weak const struct pmu_metrics_table *pmu_metrics_table__find(void) 685f8ea2c15SIan Rogers { 686f8ea2c15SIan Rogers return perf_pmu__find_metrics_table(NULL); 687f8ea2c15SIan Rogers } 688f8ea2c15SIan Rogers 689c07d5c92SJohn Garry /* 690c07d5c92SJohn Garry * Suffix must be in form tok_{digits}, or tok{digits}, or same as pmu_name 691c07d5c92SJohn Garry * to be valid. 692c07d5c92SJohn Garry */ 693c07d5c92SJohn Garry static bool perf_pmu__valid_suffix(const char *pmu_name, char *tok) 694c47a5599SJin Yao { 695c07d5c92SJohn Garry const char *p; 696c47a5599SJin Yao 697c47a5599SJin Yao if (strncmp(pmu_name, tok, strlen(tok))) 698c47a5599SJin Yao return false; 699c47a5599SJin Yao 700c47a5599SJin Yao p = pmu_name + strlen(tok); 701c47a5599SJin Yao if (*p == 0) 702c47a5599SJin Yao return true; 703c47a5599SJin Yao 704c07d5c92SJohn Garry if (*p == '_') 705c47a5599SJin Yao ++p; 706c07d5c92SJohn Garry 707c07d5c92SJohn Garry /* Ensure we end in a number */ 708c07d5c92SJohn Garry while (1) { 709c07d5c92SJohn Garry if (!isdigit(*p)) 710c47a5599SJin Yao return false; 711c07d5c92SJohn Garry if (*(++p) == 0) 712c07d5c92SJohn Garry break; 713c07d5c92SJohn Garry } 714c47a5599SJin Yao 715c47a5599SJin Yao return true; 716c47a5599SJin Yao } 717c47a5599SJin Yao 7185b9a5000SJohn Garry bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 719730670b1SJohn Garry { 720730670b1SJohn Garry char *tmp = NULL, *tok, *str; 721730670b1SJohn Garry bool res; 722730670b1SJohn Garry 723730670b1SJohn Garry str = strdup(pmu_name); 724730670b1SJohn Garry if (!str) 725730670b1SJohn Garry return false; 726730670b1SJohn Garry 727730670b1SJohn Garry /* 728730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 729730670b1SJohn Garry */ 730730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 731730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 732730670b1SJohn Garry res = false; 733730670b1SJohn Garry goto out; 734730670b1SJohn Garry } 735730670b1SJohn Garry 736730670b1SJohn Garry /* 737730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 738730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 739730670b1SJohn Garry * 740730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 741730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 742730670b1SJohn Garry * "pmunameY". 743730670b1SJohn Garry */ 744c07d5c92SJohn Garry while (1) { 745c07d5c92SJohn Garry char *next_tok = strtok_r(NULL, ",", &tmp); 746c07d5c92SJohn Garry 747730670b1SJohn Garry name = strstr(name, tok); 748c07d5c92SJohn Garry if (!name || 749c07d5c92SJohn Garry (!next_tok && !perf_pmu__valid_suffix(name, tok))) { 750730670b1SJohn Garry res = false; 751730670b1SJohn Garry goto out; 752730670b1SJohn Garry } 753c07d5c92SJohn Garry if (!next_tok) 754c07d5c92SJohn Garry break; 755c07d5c92SJohn Garry tok = next_tok; 756c07d5c92SJohn Garry name += strlen(tok); 757730670b1SJohn Garry } 758730670b1SJohn Garry 759730670b1SJohn Garry res = true; 760730670b1SJohn Garry out: 761730670b1SJohn Garry free(str); 762730670b1SJohn Garry return res; 763730670b1SJohn Garry } 764730670b1SJohn Garry 765660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data { 766660842e4SIan Rogers struct list_head *head; 767660842e4SIan Rogers const char *name; 768660842e4SIan Rogers const char *cpu_name; 769660842e4SIan Rogers struct perf_pmu *pmu; 770660842e4SIan Rogers }; 771660842e4SIan Rogers 772660842e4SIan Rogers static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, 7731ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 774660842e4SIan Rogers void *vdata) 775660842e4SIan Rogers { 776660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data *data = vdata; 777660842e4SIan Rogers const char *pname = pe->pmu ? pe->pmu : data->cpu_name; 778660842e4SIan Rogers 779660842e4SIan Rogers if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name)) 780660842e4SIan Rogers goto new_alias; 781660842e4SIan Rogers 782660842e4SIan Rogers if (strcmp(pname, data->name)) 783660842e4SIan Rogers return 0; 784660842e4SIan Rogers 785660842e4SIan Rogers new_alias: 786660842e4SIan Rogers /* need type casts to override 'const' */ 787e293a5e8SNamhyung Kim __perf_pmu__new_alias(data->head, -1, (char *)pe->name, (char *)pe->desc, 788660842e4SIan Rogers (char *)pe->event, pe); 789660842e4SIan Rogers return 0; 790660842e4SIan Rogers } 791660842e4SIan Rogers 792933f82ffSSukadev Bhattiprolu /* 793933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 794933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 795933f82ffSSukadev Bhattiprolu * as aliases. 796933f82ffSSukadev Bhattiprolu */ 797eeac7730SIan Rogers void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu, 7981ba3752aSIan Rogers const struct pmu_events_table *table) 799933f82ffSSukadev Bhattiprolu { 800660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data data = { 801660842e4SIan Rogers .head = head, 802660842e4SIan Rogers .name = pmu->name, 803660842e4SIan Rogers .cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu", 804660842e4SIan Rogers .pmu = pmu, 805660842e4SIan Rogers }; 806fedb2b51SAndi Kleen 807660842e4SIan Rogers pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data); 808933f82ffSSukadev Bhattiprolu } 809933f82ffSSukadev Bhattiprolu 810e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 811e45ad701SJohn Garry { 8121ba3752aSIan Rogers const struct pmu_events_table *table; 813e45ad701SJohn Garry 81496d2a746SIan Rogers table = perf_pmu__find_events_table(pmu); 815eeac7730SIan Rogers if (!table) 816e45ad701SJohn Garry return; 817e45ad701SJohn Garry 818eeac7730SIan Rogers pmu_add_cpu_aliases_table(head, pmu, table); 819e45ad701SJohn Garry } 820e45ad701SJohn Garry 8214513c719SJohn Garry struct pmu_sys_event_iter_data { 8224513c719SJohn Garry struct list_head *head; 8234513c719SJohn Garry struct perf_pmu *pmu; 8244513c719SJohn Garry }; 8254513c719SJohn Garry 82629be2fe0SIan Rogers static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, 8271ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 82829be2fe0SIan Rogers void *data) 8294513c719SJohn Garry { 8304513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8314513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8324513c719SJohn Garry 8334513c719SJohn Garry if (!pe->compat || !pe->pmu) 8344513c719SJohn Garry return 0; 8354513c719SJohn Garry 8364513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8374513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 838e293a5e8SNamhyung Kim __perf_pmu__new_alias(idata->head, -1, 8394513c719SJohn Garry (char *)pe->name, 8404513c719SJohn Garry (char *)pe->desc, 8414513c719SJohn Garry (char *)pe->event, 842eab35953SJin Yao pe); 8434513c719SJohn Garry } 8444513c719SJohn Garry 8454513c719SJohn Garry return 0; 8464513c719SJohn Garry } 8474513c719SJohn Garry 848e199f47fSJohn Garry void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 8494513c719SJohn Garry { 8504513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 8514513c719SJohn Garry .head = head, 8524513c719SJohn Garry .pmu = pmu, 8534513c719SJohn Garry }; 8544513c719SJohn Garry 8554513c719SJohn Garry if (!pmu->id) 8564513c719SJohn Garry return; 8574513c719SJohn Garry 8584513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 8594513c719SJohn Garry } 8604513c719SJohn Garry 861c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 862dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 863dc0a6202SAdrian Hunter { 864dc0a6202SAdrian Hunter return NULL; 865dc0a6202SAdrian Hunter } 866dc0a6202SAdrian Hunter 86713d60ba0SKan Liang char * __weak 86813d60ba0SKan Liang pmu_find_real_name(const char *name) 86913d60ba0SKan Liang { 87013d60ba0SKan Liang return (char *)name; 87113d60ba0SKan Liang } 87213d60ba0SKan Liang 87313d60ba0SKan Liang char * __weak 87413d60ba0SKan Liang pmu_find_alias_name(const char *name __maybe_unused) 87513d60ba0SKan Liang { 87613d60ba0SKan Liang return NULL; 87713d60ba0SKan Liang } 87813d60ba0SKan Liang 8793a69672eSNamhyung Kim static int pmu_max_precise(int dirfd, struct perf_pmu *pmu) 88090a86bdeSJiri Olsa { 88190a86bdeSJiri Olsa int max_precise = -1; 88290a86bdeSJiri Olsa 8833a69672eSNamhyung Kim perf_pmu__scan_file_at(pmu, dirfd, "caps/max_precise", "%d", &max_precise); 88490a86bdeSJiri Olsa return max_precise; 88590a86bdeSJiri Olsa } 88690a86bdeSJiri Olsa 887e293a5e8SNamhyung Kim static struct perf_pmu *pmu_lookup(int dirfd, const char *lookup_name) 888cd82a32eSJiri Olsa { 889cd82a32eSJiri Olsa struct perf_pmu *pmu; 890cd82a32eSJiri Olsa LIST_HEAD(format); 891a6146d50SZheng Yan LIST_HEAD(aliases); 892cd82a32eSJiri Olsa __u32 type; 89313d60ba0SKan Liang char *name = pmu_find_real_name(lookup_name); 89449afa7f6SJin Yao bool is_hybrid = perf_pmu__hybrid_mounted(name); 89513d60ba0SKan Liang char *alias_name; 89649afa7f6SJin Yao 89749afa7f6SJin Yao /* 89849afa7f6SJin Yao * Check pmu name for hybrid and the pmu may be invalid in sysfs 89949afa7f6SJin Yao */ 90049afa7f6SJin Yao if (!strncmp(name, "cpu_", 4) && !is_hybrid) 90149afa7f6SJin Yao return NULL; 902cd82a32eSJiri Olsa 903cd82a32eSJiri Olsa /* 904cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 905cd82a32eSJiri Olsa * type value and format definitions. Load both right 906cd82a32eSJiri Olsa * now. 907cd82a32eSJiri Olsa */ 908e293a5e8SNamhyung Kim if (pmu_format(dirfd, name, &format)) 909cd82a32eSJiri Olsa return NULL; 910cd82a32eSJiri Olsa 91115b22ed3SAndi Kleen /* 912f8ad6018SJames Clark * Check the aliases first to avoid unnecessary work. 91315b22ed3SAndi Kleen */ 914e293a5e8SNamhyung Kim if (pmu_aliases(dirfd, name, &aliases)) 9153fded963SJiri Olsa return NULL; 9163fded963SJiri Olsa 917cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 918cd82a32eSJiri Olsa if (!pmu) 919cd82a32eSJiri Olsa return NULL; 920cd82a32eSJiri Olsa 9213a69672eSNamhyung Kim pmu->cpus = pmu_cpumask(dirfd, name); 92254e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 923f8ad6018SJames Clark 92413d60ba0SKan Liang if (!pmu->name) 92513d60ba0SKan Liang goto err; 92613d60ba0SKan Liang 927f8ad6018SJames Clark /* Read type, and ensure that type value is successfully assigned (return 1) */ 9283a69672eSNamhyung Kim if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &type) != 1) 929f8ad6018SJames Clark goto err; 930f8ad6018SJames Clark 93113d60ba0SKan Liang alias_name = pmu_find_alias_name(name); 93213d60ba0SKan Liang if (alias_name) { 93313d60ba0SKan Liang pmu->alias_name = strdup(alias_name); 93413d60ba0SKan Liang if (!pmu->alias_name) 93513d60ba0SKan Liang goto err; 93613d60ba0SKan Liang } 93713d60ba0SKan Liang 93854e32dc0SGanapatrao Kulkarni pmu->type = type; 9393a69672eSNamhyung Kim pmu->is_uncore = pmu_is_uncore(dirfd, name); 94051d54847SJohn Garry if (pmu->is_uncore) 94151d54847SJohn Garry pmu->id = pmu_id(name); 9423a69672eSNamhyung Kim pmu->max_precise = pmu_max_precise(dirfd, pmu); 94354e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 9444513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 94566ec1191SMark Rutland 946cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 947a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 9489fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 949cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 950a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 9519bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 952dc0a6202SAdrian Hunter 953e5f4afbeSIan Rogers if (is_hybrid) 95444462430SJin Yao list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus); 955eec11310SNamhyung Kim else 956eec11310SNamhyung Kim INIT_LIST_HEAD(&pmu->hybrid_list); 95744462430SJin Yao 958dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 959dc0a6202SAdrian Hunter 960cd82a32eSJiri Olsa return pmu; 96113d60ba0SKan Liang err: 96213d60ba0SKan Liang if (pmu->name) 96313d60ba0SKan Liang free(pmu->name); 96413d60ba0SKan Liang free(pmu); 96513d60ba0SKan Liang return NULL; 966cd82a32eSJiri Olsa } 967cd82a32eSJiri Olsa 968e552b7beSRob Herring void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) 969e552b7beSRob Herring { 970e552b7beSRob Herring struct perf_pmu_format *format; 971e552b7beSRob Herring 972e552b7beSRob Herring /* fake pmu doesn't have format list */ 973e552b7beSRob Herring if (pmu == &perf_pmu__fake) 974e552b7beSRob Herring return; 975e552b7beSRob Herring 976e552b7beSRob Herring list_for_each_entry(format, &pmu->format, list) 977e552b7beSRob Herring if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) { 978e552b7beSRob Herring pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'" 979e552b7beSRob Herring "which is not supported by this version of perf!\n", 980e552b7beSRob Herring pmu->name, format->name, format->value); 981e552b7beSRob Herring return; 982e552b7beSRob Herring } 983e552b7beSRob Herring } 984e552b7beSRob Herring 985b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 986cd82a32eSJiri Olsa { 987cd82a32eSJiri Olsa struct perf_pmu *pmu; 988cd82a32eSJiri Olsa 98913d60ba0SKan Liang list_for_each_entry(pmu, &pmus, list) { 99013d60ba0SKan Liang if (!strcmp(pmu->name, name) || 99113d60ba0SKan Liang (pmu->alias_name && !strcmp(pmu->alias_name, name))) 992cd82a32eSJiri Olsa return pmu; 99313d60ba0SKan Liang } 994cd82a32eSJiri Olsa 995cd82a32eSJiri Olsa return NULL; 996cd82a32eSJiri Olsa } 997cd82a32eSJiri Olsa 9983a50dc76SStephane Eranian struct perf_pmu *perf_pmu__find_by_type(unsigned int type) 9993a50dc76SStephane Eranian { 10003a50dc76SStephane Eranian struct perf_pmu *pmu; 10013a50dc76SStephane Eranian 10023a50dc76SStephane Eranian list_for_each_entry(pmu, &pmus, list) 10033a50dc76SStephane Eranian if (pmu->type == type) 10043a50dc76SStephane Eranian return pmu; 10053a50dc76SStephane Eranian 10063a50dc76SStephane Eranian return NULL; 10073a50dc76SStephane Eranian } 10083a50dc76SStephane Eranian 100950a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 101050a9667cSRobert Richter { 101150a9667cSRobert Richter /* 101250a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 101350a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 101450a9667cSRobert Richter */ 101550a9667cSRobert Richter if (!pmu) { 101650a9667cSRobert Richter pmu_read_sysfs(); 101750a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 101850a9667cSRobert Richter } 101950a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 102050a9667cSRobert Richter return pmu; 102150a9667cSRobert Richter return NULL; 102250a9667cSRobert Richter } 102350a9667cSRobert Richter 1024c6d616feSIan Rogers struct perf_pmu *evsel__find_pmu(const struct evsel *evsel) 1025e12ee9f7SAdrian Hunter { 1026e12ee9f7SAdrian Hunter struct perf_pmu *pmu = NULL; 1027e12ee9f7SAdrian Hunter 1028f7400262SNamhyung Kim if (evsel->pmu) 1029f7400262SNamhyung Kim return evsel->pmu; 1030f7400262SNamhyung Kim 1031e12ee9f7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1032e12ee9f7SAdrian Hunter if (pmu->type == evsel->core.attr.type) 1033e12ee9f7SAdrian Hunter break; 1034e12ee9f7SAdrian Hunter } 1035e12ee9f7SAdrian Hunter 1036c6d616feSIan Rogers ((struct evsel *)evsel)->pmu = pmu; 1037e12ee9f7SAdrian Hunter return pmu; 1038e12ee9f7SAdrian Hunter } 1039e12ee9f7SAdrian Hunter 1040c6d616feSIan Rogers bool evsel__is_aux_event(const struct evsel *evsel) 1041e12ee9f7SAdrian Hunter { 1042e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 1043e12ee9f7SAdrian Hunter 1044e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 1045e12ee9f7SAdrian Hunter } 1046e12ee9f7SAdrian Hunter 1047b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 1048cd82a32eSJiri Olsa { 1049cd82a32eSJiri Olsa struct perf_pmu *pmu; 1050e293a5e8SNamhyung Kim int dirfd; 1051cd82a32eSJiri Olsa 1052cd82a32eSJiri Olsa /* 1053cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 1054cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 1055cd82a32eSJiri Olsa * the pmu format definitions. 1056cd82a32eSJiri Olsa */ 1057cd82a32eSJiri Olsa pmu = pmu_find(name); 1058cd82a32eSJiri Olsa if (pmu) 1059cd82a32eSJiri Olsa return pmu; 1060cd82a32eSJiri Olsa 1061e293a5e8SNamhyung Kim dirfd = perf_pmu__event_source_devices_fd(); 1062e293a5e8SNamhyung Kim pmu = pmu_lookup(dirfd, name); 1063e293a5e8SNamhyung Kim close(dirfd); 1064e293a5e8SNamhyung Kim 1065e293a5e8SNamhyung Kim return pmu; 1066e293a5e8SNamhyung Kim } 1067e293a5e8SNamhyung Kim 1068e293a5e8SNamhyung Kim static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name) 1069e293a5e8SNamhyung Kim { 1070e293a5e8SNamhyung Kim struct perf_pmu *pmu; 1071e293a5e8SNamhyung Kim 1072e293a5e8SNamhyung Kim /* 1073e293a5e8SNamhyung Kim * Once PMU is loaded it stays in the list, 1074e293a5e8SNamhyung Kim * so we keep us from multiple reading/parsing 1075e293a5e8SNamhyung Kim * the pmu format definitions. 1076e293a5e8SNamhyung Kim */ 1077e293a5e8SNamhyung Kim pmu = pmu_find(name); 1078e293a5e8SNamhyung Kim if (pmu) 1079e293a5e8SNamhyung Kim return pmu; 1080e293a5e8SNamhyung Kim 1081e293a5e8SNamhyung Kim return pmu_lookup(dirfd, name); 1082cd82a32eSJiri Olsa } 1083cd82a32eSJiri Olsa 10845c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 108509ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 1086cd82a32eSJiri Olsa { 10875c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1088cd82a32eSJiri Olsa 1089cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 1090cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 1091cd82a32eSJiri Olsa return format; 1092cd82a32eSJiri Olsa 1093cd82a32eSJiri Olsa return NULL; 1094cd82a32eSJiri Olsa } 1095cd82a32eSJiri Olsa 109609ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 109709ff6071SAdrian Hunter { 109809ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 109909ff6071SAdrian Hunter __u64 bits = 0; 110009ff6071SAdrian Hunter int fbit; 110109ff6071SAdrian Hunter 110209ff6071SAdrian Hunter if (!format) 110309ff6071SAdrian Hunter return 0; 110409ff6071SAdrian Hunter 110509ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 110609ff6071SAdrian Hunter bits |= 1ULL << fbit; 110709ff6071SAdrian Hunter 110809ff6071SAdrian Hunter return bits; 110909ff6071SAdrian Hunter } 111009ff6071SAdrian Hunter 1111a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1112a1ac7de6SAdrian Hunter { 1113a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1114a1ac7de6SAdrian Hunter 1115a1ac7de6SAdrian Hunter if (!format) 1116a1ac7de6SAdrian Hunter return -1; 1117a1ac7de6SAdrian Hunter 1118a1ac7de6SAdrian Hunter return format->value; 1119a1ac7de6SAdrian Hunter } 1120a1ac7de6SAdrian Hunter 1121cd82a32eSJiri Olsa /* 1122dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 11234d39c89fSIngo Molnar * and unformatted value (value parameter). 1124cd82a32eSJiri Olsa */ 1125dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1126dc0a6202SAdrian Hunter bool zero) 1127cd82a32eSJiri Olsa { 1128cd82a32eSJiri Olsa unsigned long fbit, vbit; 1129cd82a32eSJiri Olsa 1130cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1131cd82a32eSJiri Olsa 1132cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1133cd82a32eSJiri Olsa continue; 1134cd82a32eSJiri Olsa 1135dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1136dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1137dc0a6202SAdrian Hunter else if (zero) 1138dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1139cd82a32eSJiri Olsa } 1140cd82a32eSJiri Olsa } 1141cd82a32eSJiri Olsa 11420efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 11430efe6b67SAdrian Hunter { 11441b9caa10SJiri Olsa int w; 11450efe6b67SAdrian Hunter 11461b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 11471b9caa10SJiri Olsa if (!w) 11481b9caa10SJiri Olsa return 0; 11491b9caa10SJiri Olsa if (w < 64) 11501b9caa10SJiri Olsa return (1ULL << w) - 1; 11511b9caa10SJiri Olsa return -1; 11520efe6b67SAdrian Hunter } 11530efe6b67SAdrian Hunter 1154cd82a32eSJiri Olsa /* 1155688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1156688d4dfcSCody P Schafer * in the remaining terms. 1157688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1158688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1159688d4dfcSCody P Schafer * in a config string) later on in the term list. 1160688d4dfcSCody P Schafer */ 1161688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1162688d4dfcSCody P Schafer struct list_head *head_terms, 1163688d4dfcSCody P Schafer __u64 *value) 1164688d4dfcSCody P Schafer { 1165688d4dfcSCody P Schafer struct parse_events_term *t; 1166688d4dfcSCody P Schafer 1167688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 11682a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 11692a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1170688d4dfcSCody P Schafer t->used = true; 1171688d4dfcSCody P Schafer *value = t->val.num; 1172688d4dfcSCody P Schafer return 0; 1173688d4dfcSCody P Schafer } 1174688d4dfcSCody P Schafer } 1175688d4dfcSCody P Schafer 1176bb963e16SNamhyung Kim if (verbose > 0) 1177688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1178688d4dfcSCody P Schafer 1179688d4dfcSCody P Schafer return -1; 1180688d4dfcSCody P Schafer } 1181688d4dfcSCody P Schafer 1182ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1183e64b020bSJiri Olsa { 1184e64b020bSJiri Olsa struct perf_pmu_format *format; 118511db4e29SMasami Hiramatsu char *str = NULL; 118611db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1187f1417ceaSXin Gao unsigned int i = 0; 1188e64b020bSJiri Olsa 1189ffeb883eSHe Kuang if (!formats) 1190e64b020bSJiri Olsa return NULL; 1191e64b020bSJiri Olsa 1192e64b020bSJiri Olsa /* sysfs exported terms */ 1193ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 119411db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 119511db4e29SMasami Hiramatsu goto error; 1196e64b020bSJiri Olsa 1197ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 119811db4e29SMasami Hiramatsu error: 1199ffeb883eSHe Kuang strbuf_release(&buf); 1200e64b020bSJiri Olsa 1201e64b020bSJiri Olsa return str; 1202e64b020bSJiri Olsa } 1203e64b020bSJiri Olsa 1204688d4dfcSCody P Schafer /* 1205cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 120688aca8d9SCody P Schafer * user input data - term parameter. 1207cd82a32eSJiri Olsa */ 12084ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 12094ac22b48SIan Rogers struct list_head *formats, 1210cd82a32eSJiri Olsa struct perf_event_attr *attr, 1211dc0a6202SAdrian Hunter struct parse_events_term *term, 1212688d4dfcSCody P Schafer struct list_head *head_terms, 1213e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1214cd82a32eSJiri Olsa { 12155c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1216cd82a32eSJiri Olsa __u64 *vp; 12170efe6b67SAdrian Hunter __u64 val, max_val; 1218cd82a32eSJiri Olsa 1219cd82a32eSJiri Olsa /* 1220688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1221688d4dfcSCody P Schafer * skip it in normal eval. 1222688d4dfcSCody P Schafer */ 1223688d4dfcSCody P Schafer if (term->used) 1224688d4dfcSCody P Schafer return 0; 1225688d4dfcSCody P Schafer 1226688d4dfcSCody P Schafer /* 1227cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1228cd82a32eSJiri Olsa * to be done for them. 1229cd82a32eSJiri Olsa */ 1230cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1231cd82a32eSJiri Olsa return 0; 1232cd82a32eSJiri Olsa 1233cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1234688d4dfcSCody P Schafer if (!format) { 1235ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 12364ac22b48SIan Rogers char *unknown_term; 12374ac22b48SIan Rogers char *help_msg; 1238ffeb883eSHe Kuang 12394ac22b48SIan Rogers if (asprintf(&unknown_term, 12404ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 12414ac22b48SIan Rogers term->config, pmu_name) < 0) 12424ac22b48SIan Rogers unknown_term = NULL; 12434ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 12444ac22b48SIan Rogers if (err) { 12456c191289SIan Rogers parse_events_error__handle(err, term->err_term, 12464ac22b48SIan Rogers unknown_term, 12474ac22b48SIan Rogers help_msg); 12484ac22b48SIan Rogers } else { 12494ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 12504ac22b48SIan Rogers free(unknown_term); 1251e64b020bSJiri Olsa } 12524ac22b48SIan Rogers free(pmu_term); 1253cd82a32eSJiri Olsa return -EINVAL; 1254688d4dfcSCody P Schafer } 1255cd82a32eSJiri Olsa 1256cd82a32eSJiri Olsa switch (format->value) { 1257cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1258cd82a32eSJiri Olsa vp = &attr->config; 1259cd82a32eSJiri Olsa break; 1260cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1261cd82a32eSJiri Olsa vp = &attr->config1; 1262cd82a32eSJiri Olsa break; 1263cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1264cd82a32eSJiri Olsa vp = &attr->config2; 1265cd82a32eSJiri Olsa break; 1266204e7c49SRob Herring case PERF_PMU_FORMAT_VALUE_CONFIG3: 1267204e7c49SRob Herring vp = &attr->config3; 1268204e7c49SRob Herring break; 1269cd82a32eSJiri Olsa default: 1270cd82a32eSJiri Olsa return -EINVAL; 1271cd82a32eSJiri Olsa } 1272cd82a32eSJiri Olsa 127316fa7e82SJiri Olsa /* 1274688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1275688d4dfcSCody P Schafer * using event parameters. 127616fa7e82SJiri Olsa */ 127799e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 127899e7138eSJiri Olsa if (term->no_value && 127999e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 128099e7138eSJiri Olsa if (err) { 12816c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1282448d732cSIan Rogers strdup("no value assigned for term"), 1283448d732cSIan Rogers NULL); 128499e7138eSJiri Olsa } 128599e7138eSJiri Olsa return -EINVAL; 128699e7138eSJiri Olsa } 128799e7138eSJiri Olsa 1288688d4dfcSCody P Schafer val = term->val.num; 128999e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1290688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1291bb963e16SNamhyung Kim if (verbose > 0) { 1292688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1293688d4dfcSCody P Schafer term->config, term->val.str); 1294e64b020bSJiri Olsa } 1295e64b020bSJiri Olsa if (err) { 12966c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1297448d732cSIan Rogers strdup("expected numeric value"), 1298448d732cSIan Rogers NULL); 1299e64b020bSJiri Olsa } 1300688d4dfcSCody P Schafer return -EINVAL; 1301688d4dfcSCody P Schafer } 1302688d4dfcSCody P Schafer 1303688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1304688d4dfcSCody P Schafer return -EINVAL; 1305688d4dfcSCody P Schafer } else 1306688d4dfcSCody P Schafer return -EINVAL; 1307688d4dfcSCody P Schafer 13080efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 13090efe6b67SAdrian Hunter if (val > max_val) { 13100efe6b67SAdrian Hunter if (err) { 1311448d732cSIan Rogers char *err_str; 1312448d732cSIan Rogers 13136c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1314448d732cSIan Rogers asprintf(&err_str, 13150efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1316448d732cSIan Rogers (unsigned long long)max_val) < 0 1317448d732cSIan Rogers ? strdup("value too big for format") 1318448d732cSIan Rogers : err_str, 1319448d732cSIan Rogers NULL); 13200efe6b67SAdrian Hunter return -EINVAL; 13210efe6b67SAdrian Hunter } 13220efe6b67SAdrian Hunter /* 13230efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 13240efe6b67SAdrian Hunter * silently truncated. 13250efe6b67SAdrian Hunter */ 13260efe6b67SAdrian Hunter } 13270efe6b67SAdrian Hunter 1328688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1329cd82a32eSJiri Olsa return 0; 1330cd82a32eSJiri Olsa } 1331cd82a32eSJiri Olsa 13324ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1333cff7f956SJiri Olsa struct perf_event_attr *attr, 1334dc0a6202SAdrian Hunter struct list_head *head_terms, 1335e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1336cd82a32eSJiri Olsa { 13376cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1338cd82a32eSJiri Olsa 1339688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 13404ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1341e64b020bSJiri Olsa zero, err)) 1342cd82a32eSJiri Olsa return -EINVAL; 1343688d4dfcSCody P Schafer } 1344cd82a32eSJiri Olsa 1345cd82a32eSJiri Olsa return 0; 1346cd82a32eSJiri Olsa } 1347cd82a32eSJiri Olsa 1348cd82a32eSJiri Olsa /* 1349cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1350cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1351cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1352cd82a32eSJiri Olsa */ 1353cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1354e64b020bSJiri Olsa struct list_head *head_terms, 1355e64b020bSJiri Olsa struct parse_events_error *err) 1356cd82a32eSJiri Olsa { 1357dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1358dc0a6202SAdrian Hunter 1359cd82a32eSJiri Olsa attr->type = pmu->type; 13604ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 13614ac22b48SIan Rogers head_terms, zero, err); 1362cd82a32eSJiri Olsa } 1363cd82a32eSJiri Olsa 13645c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 13656cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1366a6146d50SZheng Yan { 13675c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1368a6146d50SZheng Yan char *name; 1369a6146d50SZheng Yan 1370a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1371a6146d50SZheng Yan return NULL; 1372a6146d50SZheng Yan 1373a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1374a6146d50SZheng Yan if (term->val.num != 1) 1375a6146d50SZheng Yan return NULL; 1376a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1377a6146d50SZheng Yan return NULL; 1378a6146d50SZheng Yan name = term->config; 1379a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1380a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1381a6146d50SZheng Yan return NULL; 1382a6146d50SZheng Yan name = term->val.str; 1383a6146d50SZheng Yan } else { 1384a6146d50SZheng Yan return NULL; 1385a6146d50SZheng Yan } 1386a6146d50SZheng Yan 1387a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1388a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1389a6146d50SZheng Yan return alias; 1390a6146d50SZheng Yan } 1391a6146d50SZheng Yan return NULL; 1392a6146d50SZheng Yan } 1393a6146d50SZheng Yan 1394410136f5SStephane Eranian 13951d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 13961d9e446bSJiri Olsa struct perf_pmu_info *info) 1397410136f5SStephane Eranian { 1398410136f5SStephane Eranian /* 1399410136f5SStephane Eranian * Only one term in event definition can 14001d9e446bSJiri Olsa * define unit, scale and snapshot, fail 14011d9e446bSJiri Olsa * if there's more than one. 1402410136f5SStephane Eranian */ 1403b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 14041d9e446bSJiri Olsa (info->scale && alias->scale) || 14051d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1406410136f5SStephane Eranian return -EINVAL; 1407410136f5SStephane Eranian 1408b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 14091d9e446bSJiri Olsa info->unit = alias->unit; 1410410136f5SStephane Eranian 1411410136f5SStephane Eranian if (alias->scale) 14121d9e446bSJiri Olsa info->scale = alias->scale; 14131d9e446bSJiri Olsa 14141d9e446bSJiri Olsa if (alias->snapshot) 14151d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1416410136f5SStephane Eranian 1417410136f5SStephane Eranian return 0; 1418410136f5SStephane Eranian } 1419410136f5SStephane Eranian 1420a6146d50SZheng Yan /* 1421a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1422a6146d50SZheng Yan * defined for the alias 1423a6146d50SZheng Yan */ 1424410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 142546441bdcSMatt Fleming struct perf_pmu_info *info) 1426a6146d50SZheng Yan { 14276cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 14285c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1429a6146d50SZheng Yan int ret; 1430a6146d50SZheng Yan 1431044330c1SMatt Fleming info->per_pkg = false; 1432044330c1SMatt Fleming 14338a398897SStephane Eranian /* 14348a398897SStephane Eranian * Mark unit and scale as not set 14358a398897SStephane Eranian * (different from default values, see below) 14368a398897SStephane Eranian */ 143746441bdcSMatt Fleming info->unit = NULL; 143846441bdcSMatt Fleming info->scale = 0.0; 14391d9e446bSJiri Olsa info->snapshot = false; 1440410136f5SStephane Eranian 1441a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1442a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1443a6146d50SZheng Yan if (!alias) 1444a6146d50SZheng Yan continue; 1445a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1446a6146d50SZheng Yan if (ret) 1447a6146d50SZheng Yan return ret; 1448410136f5SStephane Eranian 14491d9e446bSJiri Olsa ret = check_info_data(alias, info); 1450410136f5SStephane Eranian if (ret) 1451410136f5SStephane Eranian return ret; 1452410136f5SStephane Eranian 1453044330c1SMatt Fleming if (alias->per_pkg) 1454044330c1SMatt Fleming info->per_pkg = true; 1455044330c1SMatt Fleming 1456e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 14571dc92556SIan Rogers parse_events_term__delete(term); 1458a6146d50SZheng Yan } 14598a398897SStephane Eranian 14608a398897SStephane Eranian /* 14618a398897SStephane Eranian * if no unit or scale found in aliases, then 14628a398897SStephane Eranian * set defaults as for evsel 14638a398897SStephane Eranian * unit cannot left to NULL 14648a398897SStephane Eranian */ 146546441bdcSMatt Fleming if (info->unit == NULL) 146646441bdcSMatt Fleming info->unit = ""; 14678a398897SStephane Eranian 146846441bdcSMatt Fleming if (info->scale == 0.0) 146946441bdcSMatt Fleming info->scale = 1.0; 14708a398897SStephane Eranian 1471a6146d50SZheng Yan return 0; 1472a6146d50SZheng Yan } 1473a6146d50SZheng Yan 1474cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1475cd82a32eSJiri Olsa int config, unsigned long *bits) 1476cd82a32eSJiri Olsa { 14775c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1478cd82a32eSJiri Olsa 1479cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1480cd82a32eSJiri Olsa if (!format) 1481cd82a32eSJiri Olsa return -ENOMEM; 1482cd82a32eSJiri Olsa 1483cd82a32eSJiri Olsa format->name = strdup(name); 1484cd82a32eSJiri Olsa format->value = config; 1485cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1486cd82a32eSJiri Olsa 1487cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1488cd82a32eSJiri Olsa return 0; 1489cd82a32eSJiri Olsa } 1490cd82a32eSJiri Olsa 1491cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1492cd82a32eSJiri Olsa { 1493cd82a32eSJiri Olsa long b; 1494cd82a32eSJiri Olsa 1495cd82a32eSJiri Olsa if (!to) 1496cd82a32eSJiri Olsa to = from; 1497cd82a32eSJiri Olsa 149815268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1499cd82a32eSJiri Olsa for (b = from; b <= to; b++) 150049bd97c2SSean Christopherson __set_bit(b, bits); 1501cd82a32eSJiri Olsa } 1502dc098b35SAndi Kleen 1503d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1504d26383dcSNamhyung Kim { 1505d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1506d26383dcSNamhyung Kim 1507d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1508d26383dcSNamhyung Kim list_del(&fmt->list); 1509d26383dcSNamhyung Kim free(fmt->name); 1510d26383dcSNamhyung Kim free(fmt); 1511d26383dcSNamhyung Kim } 1512d26383dcSNamhyung Kim } 1513d26383dcSNamhyung Kim 1514aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1515aaea3617SCody P Schafer { 1516aaea3617SCody P Schafer if (b > a) 1517aaea3617SCody P Schafer return 0; 1518aaea3617SCody P Schafer return a - b; 1519aaea3617SCody P Schafer } 1520aaea3617SCody P Schafer 1521eb2d4514SIan Rogers static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, 1522eb2d4514SIan Rogers const struct perf_pmu_alias *alias) 1523dc098b35SAndi Kleen { 1524aaea3617SCody P Schafer struct parse_events_term *term; 1525aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1526aaea3617SCody P Schafer 1527aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1528aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1529aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1530aaea3617SCody P Schafer ",%s=%s", term->config, 1531aaea3617SCody P Schafer term->val.str); 1532aaea3617SCody P Schafer } 1533aaea3617SCody P Schafer 1534aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1535aaea3617SCody P Schafer buf[used] = '/'; 1536aaea3617SCody P Schafer used++; 1537aaea3617SCody P Schafer } 1538aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1539aaea3617SCody P Schafer buf[used] = '\0'; 1540aaea3617SCody P Schafer used++; 1541aaea3617SCody P Schafer } else 1542aaea3617SCody P Schafer buf[len - 1] = '\0'; 1543aaea3617SCody P Schafer 1544dc098b35SAndi Kleen return buf; 1545dc098b35SAndi Kleen } 1546dc098b35SAndi Kleen 1547eb2d4514SIan Rogers /** Struct for ordering events as output in perf list. */ 1548dd5f1036SAndi Kleen struct sevent { 1549eb2d4514SIan Rogers /** PMU for event. */ 1550eb2d4514SIan Rogers const struct perf_pmu *pmu; 1551eb2d4514SIan Rogers /** 1552eb2d4514SIan Rogers * Optional event for name, desc, etc. If not present then this is a 1553eb2d4514SIan Rogers * selectable PMU and the event name is shown as "//". 1554eb2d4514SIan Rogers */ 1555eb2d4514SIan Rogers const struct perf_pmu_alias *event; 1556eb2d4514SIan Rogers /** Is the PMU for the CPU? */ 1557eb2d4514SIan Rogers bool is_cpu; 155808e60ed1SAndi Kleen }; 155908e60ed1SAndi Kleen 1560dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1561dc098b35SAndi Kleen { 1562dd5f1036SAndi Kleen const struct sevent *as = a; 1563dd5f1036SAndi Kleen const struct sevent *bs = b; 1564eb2d4514SIan Rogers const char *a_pmu_name, *b_pmu_name; 1565eb2d4514SIan Rogers const char *a_name = "//", *a_desc = NULL, *a_topic = ""; 1566eb2d4514SIan Rogers const char *b_name = "//", *b_desc = NULL, *b_topic = ""; 15670e0ae874SJin Yao int ret; 156808e60ed1SAndi Kleen 1569eb2d4514SIan Rogers if (as->event) { 1570eb2d4514SIan Rogers a_name = as->event->name; 1571eb2d4514SIan Rogers a_desc = as->event->desc; 1572eb2d4514SIan Rogers a_topic = as->event->topic ?: ""; 1573dd5f1036SAndi Kleen } 1574eb2d4514SIan Rogers if (bs->event) { 1575eb2d4514SIan Rogers b_name = bs->event->name; 1576eb2d4514SIan Rogers b_desc = bs->event->desc; 1577eb2d4514SIan Rogers b_topic = bs->event->topic ?: ""; 1578eb2d4514SIan Rogers } 1579eb2d4514SIan Rogers /* Put extra events last. */ 1580eb2d4514SIan Rogers if (!!a_desc != !!b_desc) 1581eb2d4514SIan Rogers return !!a_desc - !!b_desc; 1582eb2d4514SIan Rogers 1583eb2d4514SIan Rogers /* Order by topics. */ 1584eb2d4514SIan Rogers ret = strcmp(a_topic, b_topic); 1585eb2d4514SIan Rogers if (ret) 1586eb2d4514SIan Rogers return ret; 1587ce0dc7d2SJohn Garry 1588ce0dc7d2SJohn Garry /* Order CPU core events to be first */ 1589ce0dc7d2SJohn Garry if (as->is_cpu != bs->is_cpu) 1590e5c6109fSIan Rogers return as->is_cpu ? -1 : 1; 1591ce0dc7d2SJohn Garry 1592eb2d4514SIan Rogers /* Order by PMU name. */ 1593eb2d4514SIan Rogers a_pmu_name = as->pmu->name ?: ""; 1594eb2d4514SIan Rogers b_pmu_name = bs->pmu->name ?: ""; 1595eb2d4514SIan Rogers ret = strcmp(a_pmu_name, b_pmu_name); 1596eb2d4514SIan Rogers if (ret) 15970e0ae874SJin Yao return ret; 1598eb2d4514SIan Rogers 1599eb2d4514SIan Rogers /* Order by event name. */ 1600eb2d4514SIan Rogers return strcmp(a_name, b_name); 160108e60ed1SAndi Kleen } 160208e60ed1SAndi Kleen 1603d504fae9SJohn Garry bool is_pmu_core(const char *name) 1604d504fae9SJohn Garry { 1605d504fae9SJohn Garry return !strcmp(name, "cpu") || is_arm_pmu_core(name); 1606d504fae9SJohn Garry } 1607d504fae9SJohn Garry 1608e0257a01SJohn Garry static bool pmu_alias_is_duplicate(struct sevent *alias_a, 1609e0257a01SJohn Garry struct sevent *alias_b) 1610e0257a01SJohn Garry { 1611eb2d4514SIan Rogers const char *a_pmu_name, *b_pmu_name; 1612eb2d4514SIan Rogers const char *a_name = alias_a->event ? alias_a->event->name : "//"; 1613eb2d4514SIan Rogers const char *b_name = alias_b->event ? alias_b->event->name : "//"; 1614eb2d4514SIan Rogers 1615e0257a01SJohn Garry /* Different names -> never duplicates */ 1616eb2d4514SIan Rogers if (strcmp(a_name, b_name)) 1617e0257a01SJohn Garry return false; 1618e0257a01SJohn Garry 1619eb2d4514SIan Rogers /* Don't remove duplicates for different PMUs */ 1620eb2d4514SIan Rogers a_pmu_name = alias_a->pmu->name ?: ""; 1621eb2d4514SIan Rogers b_pmu_name = alias_b->pmu->name ?: ""; 1622eb2d4514SIan Rogers return strcmp(a_pmu_name, b_pmu_name) == 0; 1623e0257a01SJohn Garry } 1624e0257a01SJohn Garry 1625e5c6109fSIan Rogers void print_pmu_events(const struct print_callbacks *print_cb, void *print_state) 1626dc098b35SAndi Kleen { 1627dc098b35SAndi Kleen struct perf_pmu *pmu; 1628e5c6109fSIan Rogers struct perf_pmu_alias *event; 1629dc098b35SAndi Kleen char buf[1024]; 1630dc098b35SAndi Kleen int printed = 0; 1631dc098b35SAndi Kleen int len, j; 1632dd5f1036SAndi Kleen struct sevent *aliases; 1633dc098b35SAndi Kleen 1634dc098b35SAndi Kleen pmu = NULL; 1635dc098b35SAndi Kleen len = 0; 163642634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1637e5c6109fSIan Rogers list_for_each_entry(event, &pmu->aliases, list) 1638dc098b35SAndi Kleen len++; 163942634bc7SAdrian Hunter if (pmu->selectable) 164042634bc7SAdrian Hunter len++; 164142634bc7SAdrian Hunter } 1642dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1643eb2d4514SIan Rogers if (!aliases) { 1644eb2d4514SIan Rogers pr_err("FATAL: not enough memory to print PMU events\n"); 1645eb2d4514SIan Rogers return; 1646eb2d4514SIan Rogers } 1647dc098b35SAndi Kleen pmu = NULL; 1648dc098b35SAndi Kleen j = 0; 164942634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1650e5c6109fSIan Rogers bool is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); 1651eb2d4514SIan Rogers 1652e5c6109fSIan Rogers list_for_each_entry(event, &pmu->aliases, list) { 1653e5c6109fSIan Rogers aliases[j].event = event; 1654eb2d4514SIan Rogers aliases[j].pmu = pmu; 1655ce0dc7d2SJohn Garry aliases[j].is_cpu = is_cpu; 1656dc098b35SAndi Kleen j++; 1657dc098b35SAndi Kleen } 1658e5c6109fSIan Rogers if (pmu->selectable) { 1659eb2d4514SIan Rogers aliases[j].event = NULL; 1660eb2d4514SIan Rogers aliases[j].pmu = pmu; 1661eb2d4514SIan Rogers aliases[j].is_cpu = is_cpu; 166242634bc7SAdrian Hunter j++; 166342634bc7SAdrian Hunter } 166442634bc7SAdrian Hunter } 1665dc098b35SAndi Kleen len = j; 1666dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1667dc098b35SAndi Kleen for (j = 0; j < len; j++) { 1668e5c6109fSIan Rogers const char *name, *alias = NULL, *scale_unit = NULL, 1669e5c6109fSIan Rogers *desc = NULL, *long_desc = NULL, 1670d9dc8874SIan Rogers *encoding_desc = NULL, *topic = NULL; 1671e5c6109fSIan Rogers bool deprecated = false; 1672e5c6109fSIan Rogers size_t buf_used; 1673eb2d4514SIan Rogers 167415b22ed3SAndi Kleen /* Skip duplicates */ 1675e0257a01SJohn Garry if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) 167615b22ed3SAndi Kleen continue; 16770e0ae874SJin Yao 1678eb2d4514SIan Rogers if (!aliases[j].event) { 1679eb2d4514SIan Rogers /* A selectable event. */ 1680e5c6109fSIan Rogers buf_used = snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name) + 1; 1681eb2d4514SIan Rogers name = buf; 1682eb2d4514SIan Rogers } else { 1683e5c6109fSIan Rogers if (aliases[j].event->desc) { 1684e5c6109fSIan Rogers name = aliases[j].event->name; 1685e5c6109fSIan Rogers buf_used = 0; 1686eb2d4514SIan Rogers } else { 1687eb2d4514SIan Rogers name = format_alias(buf, sizeof(buf), aliases[j].pmu, 1688eb2d4514SIan Rogers aliases[j].event); 1689e5c6109fSIan Rogers if (aliases[j].is_cpu) { 1690e5c6109fSIan Rogers alias = name; 1691e5c6109fSIan Rogers name = aliases[j].event->name; 1692eb2d4514SIan Rogers } 1693e5c6109fSIan Rogers buf_used = strlen(buf) + 1; 1694eb2d4514SIan Rogers } 1695e5c6109fSIan Rogers if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) { 1696e5c6109fSIan Rogers scale_unit = buf + buf_used; 1697e5c6109fSIan Rogers buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1698e5c6109fSIan Rogers "%G%s", aliases[j].event->scale, 1699e5c6109fSIan Rogers aliases[j].event->unit) + 1; 1700dc098b35SAndi Kleen } 1701e5c6109fSIan Rogers desc = aliases[j].event->desc; 1702e5c6109fSIan Rogers long_desc = aliases[j].event->long_desc; 1703eb2d4514SIan Rogers topic = aliases[j].event->topic; 1704e5c6109fSIan Rogers encoding_desc = buf + buf_used; 1705e5c6109fSIan Rogers buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1706e5c6109fSIan Rogers "%s/%s/", aliases[j].pmu->name, 1707e5c6109fSIan Rogers aliases[j].event->str) + 1; 1708e5c6109fSIan Rogers deprecated = aliases[j].event->deprecated; 1709dd5f1036SAndi Kleen } 1710e5c6109fSIan Rogers print_cb->print_event(print_state, 1711e5c6109fSIan Rogers aliases[j].pmu->name, 1712e5c6109fSIan Rogers topic, 1713e5c6109fSIan Rogers name, 1714e5c6109fSIan Rogers alias, 1715e5c6109fSIan Rogers scale_unit, 1716e5c6109fSIan Rogers deprecated, 1717e5c6109fSIan Rogers "Kernel PMU event", 1718e5c6109fSIan Rogers desc, 1719e5c6109fSIan Rogers long_desc, 1720d9dc8874SIan Rogers encoding_desc); 1721dc098b35SAndi Kleen } 1722dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1723dc098b35SAndi Kleen printf("\n"); 1724eb2d4514SIan Rogers 17257e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 17267e4772dcSArnaldo Carvalho de Melo return; 1727dc098b35SAndi Kleen } 17284cabc3d1SAndi Kleen 17294cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 17304cabc3d1SAndi Kleen { 17314cabc3d1SAndi Kleen struct perf_pmu *pmu; 17324cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 17334cabc3d1SAndi Kleen 17344cabc3d1SAndi Kleen pmu = NULL; 17354cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 17364cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 17374cabc3d1SAndi Kleen continue; 17384cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 17394cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 17404cabc3d1SAndi Kleen return true; 17414cabc3d1SAndi Kleen } 17424cabc3d1SAndi Kleen return false; 17434cabc3d1SAndi Kleen } 17447d4bdab5SAdrian Hunter 1745d50a79cdSJames Clark FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 17467d4bdab5SAdrian Hunter { 17477d4bdab5SAdrian Hunter char path[PATH_MAX]; 17487d4bdab5SAdrian Hunter 1749f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name) || 1750f8ad6018SJames Clark !file_available(path)) 17517d4bdab5SAdrian Hunter return NULL; 17527d4bdab5SAdrian Hunter 17537d4bdab5SAdrian Hunter return fopen(path, "r"); 17547d4bdab5SAdrian Hunter } 17557d4bdab5SAdrian Hunter 17563a69672eSNamhyung Kim FILE *perf_pmu__open_file_at(struct perf_pmu *pmu, int dirfd, const char *name) 17573a69672eSNamhyung Kim { 17583a69672eSNamhyung Kim int fd; 17593a69672eSNamhyung Kim 17603a69672eSNamhyung Kim fd = perf_pmu__pathname_fd(dirfd, pmu->name, name, O_RDONLY); 17613a69672eSNamhyung Kim if (fd < 0) 17623a69672eSNamhyung Kim return NULL; 17633a69672eSNamhyung Kim 17643a69672eSNamhyung Kim return fdopen(fd, "r"); 17653a69672eSNamhyung Kim } 17663a69672eSNamhyung Kim 17677d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 17687d4bdab5SAdrian Hunter ...) 17697d4bdab5SAdrian Hunter { 17707d4bdab5SAdrian Hunter va_list args; 17717d4bdab5SAdrian Hunter FILE *file; 17727d4bdab5SAdrian Hunter int ret = EOF; 17737d4bdab5SAdrian Hunter 17747d4bdab5SAdrian Hunter va_start(args, fmt); 17757d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 17767d4bdab5SAdrian Hunter if (file) { 17777d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 17787d4bdab5SAdrian Hunter fclose(file); 17797d4bdab5SAdrian Hunter } 17807d4bdab5SAdrian Hunter va_end(args); 17817d4bdab5SAdrian Hunter return ret; 17827d4bdab5SAdrian Hunter } 17839fbc61f8SKan Liang 17843a69672eSNamhyung Kim int perf_pmu__scan_file_at(struct perf_pmu *pmu, int dirfd, const char *name, 17853a69672eSNamhyung Kim const char *fmt, ...) 17863a69672eSNamhyung Kim { 17873a69672eSNamhyung Kim va_list args; 17883a69672eSNamhyung Kim FILE *file; 17893a69672eSNamhyung Kim int ret = EOF; 17903a69672eSNamhyung Kim 17913a69672eSNamhyung Kim va_start(args, fmt); 17923a69672eSNamhyung Kim file = perf_pmu__open_file_at(pmu, dirfd, name); 17933a69672eSNamhyung Kim if (file) { 17943a69672eSNamhyung Kim ret = vfscanf(file, fmt, args); 17953a69672eSNamhyung Kim fclose(file); 17963a69672eSNamhyung Kim } 17973a69672eSNamhyung Kim va_end(args); 17983a69672eSNamhyung Kim return ret; 17993a69672eSNamhyung Kim } 18003a69672eSNamhyung Kim 1801c2b6a896SGerman Gomez bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name) 1802c2b6a896SGerman Gomez { 1803c2b6a896SGerman Gomez char path[PATH_MAX]; 1804c2b6a896SGerman Gomez 1805c2b6a896SGerman Gomez if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name)) 1806c2b6a896SGerman Gomez return false; 1807c2b6a896SGerman Gomez 1808c2b6a896SGerman Gomez return file_available(path); 1809c2b6a896SGerman Gomez } 1810c2b6a896SGerman Gomez 18119fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 18129fbc61f8SKan Liang { 18139fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 18149fbc61f8SKan Liang 18159fbc61f8SKan Liang if (!caps) 18169fbc61f8SKan Liang return -ENOMEM; 18179fbc61f8SKan Liang 18189fbc61f8SKan Liang caps->name = strdup(name); 18199fbc61f8SKan Liang if (!caps->name) 18209fbc61f8SKan Liang goto free_caps; 18219fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 18229fbc61f8SKan Liang if (!caps->value) 18239fbc61f8SKan Liang goto free_name; 18249fbc61f8SKan Liang list_add_tail(&caps->list, list); 18259fbc61f8SKan Liang return 0; 18269fbc61f8SKan Liang 18279fbc61f8SKan Liang free_name: 18289fbc61f8SKan Liang zfree(caps->name); 18299fbc61f8SKan Liang free_caps: 18309fbc61f8SKan Liang free(caps); 18319fbc61f8SKan Liang 18329fbc61f8SKan Liang return -ENOMEM; 18339fbc61f8SKan Liang } 18349fbc61f8SKan Liang 1835eec11310SNamhyung Kim static void perf_pmu__del_caps(struct perf_pmu *pmu) 1836eec11310SNamhyung Kim { 1837eec11310SNamhyung Kim struct perf_pmu_caps *caps, *tmp; 1838eec11310SNamhyung Kim 1839eec11310SNamhyung Kim list_for_each_entry_safe(caps, tmp, &pmu->caps, list) { 1840eec11310SNamhyung Kim list_del(&caps->list); 1841eec11310SNamhyung Kim free(caps->name); 1842eec11310SNamhyung Kim free(caps->value); 1843eec11310SNamhyung Kim free(caps); 1844eec11310SNamhyung Kim } 1845eec11310SNamhyung Kim } 1846eec11310SNamhyung Kim 18479fbc61f8SKan Liang /* 18489fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 18499fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 18509fbc61f8SKan Liang * Return the number of capabilities 18519fbc61f8SKan Liang */ 18529fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 18539fbc61f8SKan Liang { 18549fbc61f8SKan Liang struct stat st; 18559fbc61f8SKan Liang char caps_path[PATH_MAX]; 18569fbc61f8SKan Liang DIR *caps_dir; 18579fbc61f8SKan Liang struct dirent *evt_ent; 1858b39094d3SNamhyung Kim int caps_fd; 18593339ec44SRavi Bangoria 18603339ec44SRavi Bangoria if (pmu->caps_initialized) 18613339ec44SRavi Bangoria return pmu->nr_caps; 18623339ec44SRavi Bangoria 18633339ec44SRavi Bangoria pmu->nr_caps = 0; 18649fbc61f8SKan Liang 1865f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name, "caps")) 18669fbc61f8SKan Liang return -1; 18679fbc61f8SKan Liang 18683339ec44SRavi Bangoria if (stat(caps_path, &st) < 0) { 18693339ec44SRavi Bangoria pmu->caps_initialized = true; 18709fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 18713339ec44SRavi Bangoria } 18729fbc61f8SKan Liang 18739fbc61f8SKan Liang caps_dir = opendir(caps_path); 18749fbc61f8SKan Liang if (!caps_dir) 18759fbc61f8SKan Liang return -EINVAL; 18769fbc61f8SKan Liang 1877b39094d3SNamhyung Kim caps_fd = dirfd(caps_dir); 1878b39094d3SNamhyung Kim 18799fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 18809fbc61f8SKan Liang char *name = evt_ent->d_name; 18819fbc61f8SKan Liang char value[128]; 18829fbc61f8SKan Liang FILE *file; 1883b39094d3SNamhyung Kim int fd; 18849fbc61f8SKan Liang 18859fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 18869fbc61f8SKan Liang continue; 18879fbc61f8SKan Liang 1888b39094d3SNamhyung Kim fd = openat(caps_fd, name, O_RDONLY); 18890ea8920eSIan Rogers if (fd == -1) 18909fbc61f8SKan Liang continue; 18910ea8920eSIan Rogers file = fdopen(fd, "r"); 18920ea8920eSIan Rogers if (!file) { 18930ea8920eSIan Rogers close(fd); 18940ea8920eSIan Rogers continue; 18950ea8920eSIan Rogers } 18969fbc61f8SKan Liang 18979fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 18989fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 18999fbc61f8SKan Liang fclose(file); 19009fbc61f8SKan Liang continue; 19019fbc61f8SKan Liang } 19029fbc61f8SKan Liang 19033339ec44SRavi Bangoria pmu->nr_caps++; 19049fbc61f8SKan Liang fclose(file); 19059fbc61f8SKan Liang } 19069fbc61f8SKan Liang 19079fbc61f8SKan Liang closedir(caps_dir); 19089fbc61f8SKan Liang 19093339ec44SRavi Bangoria pmu->caps_initialized = true; 19103339ec44SRavi Bangoria return pmu->nr_caps; 19119fbc61f8SKan Liang } 1912e4064776SJin Yao 1913e4064776SJin Yao void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 19148e8bbfb3SIan Rogers const char *name) 1915e4064776SJin Yao { 1916e4064776SJin Yao struct perf_pmu_format *format; 1917e4064776SJin Yao __u64 masks = 0, bits; 1918e4064776SJin Yao char buf[100]; 1919e4064776SJin Yao unsigned int i; 1920e4064776SJin Yao 1921e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1922e4064776SJin Yao if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG) 1923e4064776SJin Yao continue; 1924e4064776SJin Yao 1925e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1926e4064776SJin Yao masks |= 1ULL << i; 1927e4064776SJin Yao } 1928e4064776SJin Yao 1929e4064776SJin Yao /* 1930e4064776SJin Yao * Kernel doesn't export any valid format bits. 1931e4064776SJin Yao */ 1932e4064776SJin Yao if (masks == 0) 1933e4064776SJin Yao return; 1934e4064776SJin Yao 1935e4064776SJin Yao bits = config & ~masks; 1936e4064776SJin Yao if (bits == 0) 1937e4064776SJin Yao return; 1938e4064776SJin Yao 1939e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1940e4064776SJin Yao 1941e4064776SJin Yao pr_warning("WARNING: event '%s' not valid (bits %s of config " 1942e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1943e4064776SJin Yao name ?: "N/A", buf, config); 1944e4064776SJin Yao } 1945c5a26ea4SJin Yao 1946c5a26ea4SJin Yao bool perf_pmu__has_hybrid(void) 1947c5a26ea4SJin Yao { 1948c5a26ea4SJin Yao if (!hybrid_scanned) { 1949c5a26ea4SJin Yao hybrid_scanned = true; 1950c5a26ea4SJin Yao perf_pmu__scan(NULL); 1951c5a26ea4SJin Yao } 1952c5a26ea4SJin Yao 1953c5a26ea4SJin Yao return !list_empty(&perf_pmu__hybrid_pmus); 1954c5a26ea4SJin Yao } 1955c47a5599SJin Yao 1956c47a5599SJin Yao int perf_pmu__match(char *pattern, char *name, char *tok) 1957c47a5599SJin Yao { 195813d60ba0SKan Liang if (!name) 195913d60ba0SKan Liang return -1; 196013d60ba0SKan Liang 1961c47a5599SJin Yao if (fnmatch(pattern, name, 0)) 1962c47a5599SJin Yao return -1; 1963c47a5599SJin Yao 1964c47a5599SJin Yao if (tok && !perf_pmu__valid_suffix(name, tok)) 1965c47a5599SJin Yao return -1; 1966c47a5599SJin Yao 1967c47a5599SJin Yao return 0; 1968c47a5599SJin Yao } 19691d3351e6SJin Yao 19701d3351e6SJin Yao int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus, 19711d3351e6SJin Yao struct perf_cpu_map **mcpus_ptr, 19721d3351e6SJin Yao struct perf_cpu_map **ucpus_ptr) 19731d3351e6SJin Yao { 19741d3351e6SJin Yao struct perf_cpu_map *pmu_cpus = pmu->cpus; 19751d3351e6SJin Yao struct perf_cpu_map *matched_cpus, *unmatched_cpus; 19766a12a63eSIan Rogers struct perf_cpu cpu; 19776a12a63eSIan Rogers int i, matched_nr = 0, unmatched_nr = 0; 19781d3351e6SJin Yao 19791d3351e6SJin Yao matched_cpus = perf_cpu_map__default_new(); 19801d3351e6SJin Yao if (!matched_cpus) 19811d3351e6SJin Yao return -1; 19821d3351e6SJin Yao 19831d3351e6SJin Yao unmatched_cpus = perf_cpu_map__default_new(); 19841d3351e6SJin Yao if (!unmatched_cpus) { 19851d3351e6SJin Yao perf_cpu_map__put(matched_cpus); 19861d3351e6SJin Yao return -1; 19871d3351e6SJin Yao } 19881d3351e6SJin Yao 19896a12a63eSIan Rogers perf_cpu_map__for_each_cpu(cpu, i, cpus) { 19906a12a63eSIan Rogers if (!perf_cpu_map__has(pmu_cpus, cpu)) 19916a12a63eSIan Rogers unmatched_cpus->map[unmatched_nr++] = cpu; 19921d3351e6SJin Yao else 19936a12a63eSIan Rogers matched_cpus->map[matched_nr++] = cpu; 19941d3351e6SJin Yao } 19951d3351e6SJin Yao 19961d3351e6SJin Yao unmatched_cpus->nr = unmatched_nr; 19971d3351e6SJin Yao matched_cpus->nr = matched_nr; 19981d3351e6SJin Yao *mcpus_ptr = matched_cpus; 19991d3351e6SJin Yao *ucpus_ptr = unmatched_cpus; 20001d3351e6SJin Yao return 0; 20011d3351e6SJin Yao } 2002acef233bSJing Zhang 2003acef233bSJing Zhang double __weak perf_pmu__cpu_slots_per_cycle(void) 2004acef233bSJing Zhang { 2005acef233bSJing Zhang return NAN; 2006acef233bSJing Zhang } 2007f8ad6018SJames Clark 2008f8ad6018SJames Clark int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size) 2009f8ad6018SJames Clark { 2010f8ad6018SJames Clark const char *sysfs = sysfs__mountpoint(); 2011f8ad6018SJames Clark 2012f8ad6018SJames Clark if (!sysfs) 2013f8ad6018SJames Clark return 0; 2014f8ad6018SJames Clark return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs); 2015f8ad6018SJames Clark } 2016f8ad6018SJames Clark 2017e293a5e8SNamhyung Kim int perf_pmu__event_source_devices_fd(void) 2018e293a5e8SNamhyung Kim { 2019e293a5e8SNamhyung Kim char path[PATH_MAX]; 2020e293a5e8SNamhyung Kim const char *sysfs = sysfs__mountpoint(); 2021e293a5e8SNamhyung Kim 2022e293a5e8SNamhyung Kim if (!sysfs) 2023e293a5e8SNamhyung Kim return -1; 2024e293a5e8SNamhyung Kim 2025e293a5e8SNamhyung Kim scnprintf(path, sizeof(path), "%s/bus/event_source/devices/", sysfs); 2026e293a5e8SNamhyung Kim return open(path, O_DIRECTORY); 2027e293a5e8SNamhyung Kim } 2028e293a5e8SNamhyung Kim 2029f8ad6018SJames Clark /* 2030f8ad6018SJames Clark * Fill 'buf' with the path to a file or folder in 'pmu_name' in 2031f8ad6018SJames Clark * sysfs. For example if pmu_name = "cs_etm" and 'filename' = "format" 2032f8ad6018SJames Clark * then pathname will be filled with 2033f8ad6018SJames Clark * "/sys/bus/event_source/devices/cs_etm/format" 2034f8ad6018SJames Clark * 2035f8ad6018SJames Clark * Return 0 if the sysfs mountpoint couldn't be found or if no 2036f8ad6018SJames Clark * characters were written. 2037f8ad6018SJames Clark */ 2038f8ad6018SJames Clark int perf_pmu__pathname_scnprintf(char *buf, size_t size, 2039f8ad6018SJames Clark const char *pmu_name, const char *filename) 2040f8ad6018SJames Clark { 2041f8ad6018SJames Clark char base_path[PATH_MAX]; 2042f8ad6018SJames Clark 2043f8ad6018SJames Clark if (!perf_pmu__event_source_devices_scnprintf(base_path, sizeof(base_path))) 2044f8ad6018SJames Clark return 0; 2045f8ad6018SJames Clark return scnprintf(buf, size, "%s%s/%s", base_path, pmu_name, filename); 2046f8ad6018SJames Clark } 2047eec11310SNamhyung Kim 2048e293a5e8SNamhyung Kim int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags) 2049e293a5e8SNamhyung Kim { 2050e293a5e8SNamhyung Kim char path[PATH_MAX]; 2051e293a5e8SNamhyung Kim 2052e293a5e8SNamhyung Kim scnprintf(path, sizeof(path), "%s/%s", pmu_name, filename); 2053e293a5e8SNamhyung Kim return openat(dirfd, path, flags); 2054e293a5e8SNamhyung Kim } 2055e293a5e8SNamhyung Kim 2056eec11310SNamhyung Kim static void perf_pmu__delete(struct perf_pmu *pmu) 2057eec11310SNamhyung Kim { 2058eec11310SNamhyung Kim perf_pmu__del_formats(&pmu->format); 2059eec11310SNamhyung Kim perf_pmu__del_aliases(pmu); 2060eec11310SNamhyung Kim perf_pmu__del_caps(pmu); 2061eec11310SNamhyung Kim 2062eec11310SNamhyung Kim perf_cpu_map__put(pmu->cpus); 2063eec11310SNamhyung Kim 2064eec11310SNamhyung Kim free(pmu->default_config); 2065eec11310SNamhyung Kim free(pmu->name); 2066eec11310SNamhyung Kim free(pmu->alias_name); 2067eec11310SNamhyung Kim free(pmu); 2068eec11310SNamhyung Kim } 2069eec11310SNamhyung Kim 2070eec11310SNamhyung Kim void perf_pmu__destroy(void) 2071eec11310SNamhyung Kim { 2072eec11310SNamhyung Kim struct perf_pmu *pmu, *tmp; 2073eec11310SNamhyung Kim 2074eec11310SNamhyung Kim list_for_each_entry_safe(pmu, tmp, &pmus, list) { 2075eec11310SNamhyung Kim list_del(&pmu->list); 2076eec11310SNamhyung Kim list_del(&pmu->hybrid_list); 2077eec11310SNamhyung Kim 2078eec11310SNamhyung Kim perf_pmu__delete(pmu); 2079eec11310SNamhyung Kim } 2080eec11310SNamhyung Kim } 2081