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" 27cd82a32eSJiri Olsa #include "parse-events.h" 28e5c6109fSIan Rogers #include "print-events.h" 29933f82ffSSukadev Bhattiprolu #include "header.h" 30a067558eSArnaldo Carvalho de Melo #include "string2.h" 31fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h" 32d9664582SAndi Kleen #include "fncache.h" 3344462430SJin Yao #include "pmu-hybrid.h" 34cd82a32eSJiri Olsa 35e46fc8d9SArnaldo Carvalho de Melo struct perf_pmu perf_pmu__fake; 36e46fc8d9SArnaldo Carvalho de Melo 37fe13d43dSIan Rogers /** 38fe13d43dSIan Rogers * struct perf_pmu_format - Values from a format file read from 39fe13d43dSIan Rogers * <sysfs>/devices/cpu/format/ held in struct perf_pmu. 40fe13d43dSIan Rogers * 41fe13d43dSIan Rogers * For example, the contents of <sysfs>/devices/cpu/format/event may be 42fe13d43dSIan Rogers * "config:0-7" and will be represented here as name="event", 43fe13d43dSIan Rogers * value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set. 44fe13d43dSIan Rogers */ 45ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 46fe13d43dSIan Rogers /** @name: The modifier/file name. */ 47ab1bf653SArnaldo Carvalho de Melo char *name; 48fe13d43dSIan Rogers /** 49fe13d43dSIan Rogers * @value : Which config value the format relates to. Supported values 50fe13d43dSIan Rogers * are from PERF_PMU_FORMAT_VALUE_CONFIG to 51fe13d43dSIan Rogers * PERF_PMU_FORMAT_VALUE_CONFIG_END. 52fe13d43dSIan Rogers */ 53ab1bf653SArnaldo Carvalho de Melo int value; 54fe13d43dSIan Rogers /** @bits: Which config bits are set by this format value. */ 55ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 56fe13d43dSIan Rogers /** @list: Element on list within struct perf_pmu. */ 57ab1bf653SArnaldo Carvalho de Melo struct list_head list; 58ab1bf653SArnaldo Carvalho de Melo }; 59ab1bf653SArnaldo Carvalho de Melo 60cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 61cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 62cd82a32eSJiri Olsa 63c5a26ea4SJin Yao static bool hybrid_scanned; 64cd82a32eSJiri Olsa 65cd82a32eSJiri Olsa /* 66cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 67cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 68cd82a32eSJiri Olsa */ 69cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 70cd82a32eSJiri Olsa { 71cd82a32eSJiri Olsa struct dirent *evt_ent; 72cd82a32eSJiri Olsa DIR *format_dir; 73cd82a32eSJiri Olsa int ret = 0; 74cd82a32eSJiri Olsa 75cd82a32eSJiri Olsa format_dir = opendir(dir); 76cd82a32eSJiri Olsa if (!format_dir) 77cd82a32eSJiri Olsa return -EINVAL; 78cd82a32eSJiri Olsa 79cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 80cd82a32eSJiri Olsa char path[PATH_MAX]; 81cd82a32eSJiri Olsa char *name = evt_ent->d_name; 82cd82a32eSJiri Olsa FILE *file; 83cd82a32eSJiri Olsa 84cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 85cd82a32eSJiri Olsa continue; 86cd82a32eSJiri Olsa 87cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 88cd82a32eSJiri Olsa 89cd82a32eSJiri Olsa ret = -EINVAL; 90cd82a32eSJiri Olsa file = fopen(path, "r"); 91cd82a32eSJiri Olsa if (!file) 92cd82a32eSJiri Olsa break; 93cd82a32eSJiri Olsa 94cd82a32eSJiri Olsa perf_pmu_in = file; 95cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 96cd82a32eSJiri Olsa fclose(file); 97cd82a32eSJiri Olsa } 98cd82a32eSJiri Olsa 99cd82a32eSJiri Olsa closedir(format_dir); 100cd82a32eSJiri Olsa return ret; 101cd82a32eSJiri Olsa } 102cd82a32eSJiri Olsa 103cd82a32eSJiri Olsa /* 104cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 105cd82a32eSJiri Olsa * located at: 106cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 107cd82a32eSJiri Olsa */ 108b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 109cd82a32eSJiri Olsa { 110cd82a32eSJiri Olsa char path[PATH_MAX]; 111cd82a32eSJiri Olsa 112f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "format")) 113cd82a32eSJiri Olsa return -1; 114cd82a32eSJiri Olsa 115d9664582SAndi Kleen if (!file_available(path)) 116d9664582SAndi Kleen return 0; 117cd82a32eSJiri Olsa 118cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 119cd82a32eSJiri Olsa return -1; 120cd82a32eSJiri Olsa 121cd82a32eSJiri Olsa return 0; 122cd82a32eSJiri Olsa } 123cd82a32eSJiri Olsa 124a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 125d02fc6bcSAndi Kleen { 126d02fc6bcSAndi Kleen char *lc; 127d02fc6bcSAndi Kleen int ret = 0; 128d02fc6bcSAndi Kleen 129d02fc6bcSAndi Kleen /* 130d02fc6bcSAndi Kleen * save current locale 131d02fc6bcSAndi Kleen */ 132d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 133d02fc6bcSAndi Kleen 134d02fc6bcSAndi Kleen /* 135d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 136d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 137d02fc6bcSAndi Kleen * call below. 138d02fc6bcSAndi Kleen */ 139d02fc6bcSAndi Kleen lc = strdup(lc); 140d02fc6bcSAndi Kleen if (!lc) { 141d02fc6bcSAndi Kleen ret = -ENOMEM; 142d02fc6bcSAndi Kleen goto out; 143d02fc6bcSAndi Kleen } 144d02fc6bcSAndi Kleen 145d02fc6bcSAndi Kleen /* 146d02fc6bcSAndi Kleen * force to C locale to ensure kernel 147d02fc6bcSAndi Kleen * scale string is converted correctly. 148d02fc6bcSAndi Kleen * kernel uses default C locale. 149d02fc6bcSAndi Kleen */ 150d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 151d02fc6bcSAndi Kleen 152d02fc6bcSAndi Kleen *sval = strtod(scale, end); 153d02fc6bcSAndi Kleen 154d02fc6bcSAndi Kleen out: 155d02fc6bcSAndi Kleen /* restore locale */ 156d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 157d02fc6bcSAndi Kleen free(lc); 158d02fc6bcSAndi Kleen return ret; 159d02fc6bcSAndi Kleen } 160d02fc6bcSAndi Kleen 161410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 162410136f5SStephane Eranian { 163410136f5SStephane Eranian struct stat st; 164410136f5SStephane Eranian ssize_t sret; 165410136f5SStephane Eranian char scale[128]; 166410136f5SStephane Eranian int fd, ret = -1; 167410136f5SStephane Eranian char path[PATH_MAX]; 168410136f5SStephane Eranian 16911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 170410136f5SStephane Eranian 171410136f5SStephane Eranian fd = open(path, O_RDONLY); 172410136f5SStephane Eranian if (fd == -1) 173410136f5SStephane Eranian return -1; 174410136f5SStephane Eranian 175410136f5SStephane Eranian if (fstat(fd, &st) < 0) 176410136f5SStephane Eranian goto error; 177410136f5SStephane Eranian 178410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 179410136f5SStephane Eranian if (sret < 0) 180410136f5SStephane Eranian goto error; 181410136f5SStephane Eranian 1829ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1839ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1849ecae065SMadhavan Srinivasan else 185410136f5SStephane Eranian scale[sret] = '\0'; 1869ecae065SMadhavan Srinivasan 187a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 188410136f5SStephane Eranian error: 189410136f5SStephane Eranian close(fd); 190410136f5SStephane Eranian return ret; 191410136f5SStephane Eranian } 192410136f5SStephane Eranian 193410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 194410136f5SStephane Eranian { 195410136f5SStephane Eranian char path[PATH_MAX]; 196410136f5SStephane Eranian ssize_t sret; 197410136f5SStephane Eranian int fd; 198410136f5SStephane Eranian 19911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 200410136f5SStephane Eranian 201410136f5SStephane Eranian fd = open(path, O_RDONLY); 202410136f5SStephane Eranian if (fd == -1) 203410136f5SStephane Eranian return -1; 204410136f5SStephane Eranian 205410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 206410136f5SStephane Eranian if (sret < 0) 207410136f5SStephane Eranian goto error; 208410136f5SStephane Eranian 209410136f5SStephane Eranian close(fd); 210410136f5SStephane Eranian 2119ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 2129ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 2139ecae065SMadhavan Srinivasan else 214410136f5SStephane Eranian alias->unit[sret] = '\0'; 215410136f5SStephane Eranian 216410136f5SStephane Eranian return 0; 217410136f5SStephane Eranian error: 218410136f5SStephane Eranian close(fd); 219410136f5SStephane Eranian alias->unit[0] = '\0'; 220410136f5SStephane Eranian return -1; 221410136f5SStephane Eranian } 222410136f5SStephane Eranian 223044330c1SMatt Fleming static int 224044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 225044330c1SMatt Fleming { 226044330c1SMatt Fleming char path[PATH_MAX]; 227044330c1SMatt Fleming int fd; 228044330c1SMatt Fleming 22911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 230044330c1SMatt Fleming 231044330c1SMatt Fleming fd = open(path, O_RDONLY); 232044330c1SMatt Fleming if (fd == -1) 233044330c1SMatt Fleming return -1; 234044330c1SMatt Fleming 235044330c1SMatt Fleming close(fd); 236044330c1SMatt Fleming 237044330c1SMatt Fleming alias->per_pkg = true; 238044330c1SMatt Fleming return 0; 239044330c1SMatt Fleming } 240044330c1SMatt Fleming 2411d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2421d9e446bSJiri Olsa char *dir, char *name) 2431d9e446bSJiri Olsa { 2441d9e446bSJiri Olsa char path[PATH_MAX]; 2451d9e446bSJiri Olsa int fd; 2461d9e446bSJiri Olsa 24711a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2481d9e446bSJiri Olsa 2491d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2501d9e446bSJiri Olsa if (fd == -1) 2511d9e446bSJiri Olsa return -1; 2521d9e446bSJiri Olsa 2531d9e446bSJiri Olsa alias->snapshot = true; 2541d9e446bSJiri Olsa close(fd); 2551d9e446bSJiri Olsa return 0; 2561d9e446bSJiri Olsa } 2571d9e446bSJiri Olsa 2586dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2596dde6429SThomas Richter char **new_str) 2606dde6429SThomas Richter { 2616dde6429SThomas Richter if (!*old_str) 2626dde6429SThomas Richter goto set_new; 2636dde6429SThomas Richter 2646dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2656dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2666dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2676dde6429SThomas Richter name, field); 2686dde6429SThomas Richter zfree(old_str); 2696dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2706dde6429SThomas Richter return; 2716dde6429SThomas Richter set_new: 2726dde6429SThomas Richter *old_str = *new_str; 2736dde6429SThomas Richter *new_str = NULL; 2746dde6429SThomas Richter } 2756dde6429SThomas Richter 2766dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2776dde6429SThomas Richter struct perf_pmu_alias *newalias) 2786dde6429SThomas Richter { 2796dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2806dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2816dde6429SThomas Richter &newalias->long_desc); 2826dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2836dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, 2846dde6429SThomas Richter &newalias->metric_expr); 2856dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, 2866dde6429SThomas Richter &newalias->metric_name); 2876dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2886dde6429SThomas Richter old->scale = newalias->scale; 2896dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2906dde6429SThomas Richter old->snapshot = newalias->snapshot; 2916dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2926dde6429SThomas Richter } 2936dde6429SThomas Richter 2946dde6429SThomas Richter /* Delete an alias entry. */ 29522fe5a25SNamhyung Kim void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2966dde6429SThomas Richter { 2976dde6429SThomas Richter zfree(&newalias->name); 2986dde6429SThomas Richter zfree(&newalias->desc); 2996dde6429SThomas Richter zfree(&newalias->long_desc); 3006dde6429SThomas Richter zfree(&newalias->topic); 3016dde6429SThomas Richter zfree(&newalias->str); 3026dde6429SThomas Richter zfree(&newalias->metric_expr); 3036dde6429SThomas Richter zfree(&newalias->metric_name); 30432705de7SJin Yao zfree(&newalias->pmu_name); 3056dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 3066dde6429SThomas Richter free(newalias); 3076dde6429SThomas Richter } 3086dde6429SThomas Richter 3096dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 3106dde6429SThomas Richter * present merge both of them to combine all information. 3116dde6429SThomas Richter */ 3126dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 3136dde6429SThomas Richter struct list_head *alist) 3146dde6429SThomas Richter { 3156dde6429SThomas Richter struct perf_pmu_alias *a; 3166dde6429SThomas Richter 3176dde6429SThomas Richter list_for_each_entry(a, alist, list) { 3186dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 31932705de7SJin Yao if (newalias->pmu_name && a->pmu_name && 32032705de7SJin Yao !strcasecmp(newalias->pmu_name, a->pmu_name)) { 32132705de7SJin Yao continue; 32232705de7SJin Yao } 3236dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 3246dde6429SThomas Richter perf_pmu_free_alias(newalias); 3256dde6429SThomas Richter return true; 3266dde6429SThomas Richter } 3276dde6429SThomas Richter } 3286dde6429SThomas Richter return false; 3296dde6429SThomas Richter } 3306dde6429SThomas Richter 33170c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 33247f572aaSIan Rogers char *desc, char *val, const struct pmu_event *pe) 333a6146d50SZheng Yan { 3340c24d6fbSThomas Richter struct parse_events_term *term; 3355c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 336a6146d50SZheng Yan int ret; 337fedb2b51SAndi Kleen int num; 3380c24d6fbSThomas Richter char newval[256]; 339eab35953SJin Yao char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL, 34032705de7SJin Yao *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL, 34132705de7SJin Yao *pmu_name = NULL; 342eab35953SJin Yao 343eab35953SJin Yao if (pe) { 344eab35953SJin Yao long_desc = (char *)pe->long_desc; 345eab35953SJin Yao topic = (char *)pe->topic; 346eab35953SJin Yao unit = (char *)pe->unit; 347eab35953SJin Yao perpkg = (char *)pe->perpkg; 348eab35953SJin Yao metric_expr = (char *)pe->metric_expr; 349eab35953SJin Yao metric_name = (char *)pe->metric_name; 350eab35953SJin Yao deprecated = (char *)pe->deprecated; 35132705de7SJin Yao pmu_name = (char *)pe->pmu; 352eab35953SJin Yao } 353a6146d50SZheng Yan 354a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 355a6146d50SZheng Yan if (!alias) 356a6146d50SZheng Yan return -ENOMEM; 357a6146d50SZheng Yan 358a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 359410136f5SStephane Eranian alias->scale = 1.0; 360410136f5SStephane Eranian alias->unit[0] = '\0'; 361044330c1SMatt Fleming alias->per_pkg = false; 36284530920SStephane Eranian alias->snapshot = false; 363a7f6c8c8SJin Yao alias->deprecated = false; 364410136f5SStephane Eranian 36570c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 366a6146d50SZheng Yan if (ret) { 36770c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 368a6146d50SZheng Yan free(alias); 369a6146d50SZheng Yan return ret; 370a6146d50SZheng Yan } 371a6146d50SZheng Yan 3720c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3730c24d6fbSThomas Richter * platforms have terms specified as 3740c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3750c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3760c24d6fbSThomas Richter * 3770c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3780c24d6fbSThomas Richter */ 3790c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3800c24d6fbSThomas Richter ret = 0; 3810c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3820c24d6fbSThomas Richter if (ret) 3830c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3840c24d6fbSThomas Richter ","); 3850c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3860c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3870c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3880c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3890c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3900c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3910c24d6fbSThomas Richter } 3920c24d6fbSThomas Richter 393a6146d50SZheng Yan alias->name = strdup(name); 39470c646e0SSukadev Bhattiprolu if (dir) { 395410136f5SStephane Eranian /* 396410136f5SStephane Eranian * load unit name and scale if available 397410136f5SStephane Eranian */ 398410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 399410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 400044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 4011d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 40270c646e0SSukadev Bhattiprolu } 403410136f5SStephane Eranian 40400636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 40596284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 40608e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 407c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 408c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 409dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 410fedb2b51SAndi Kleen if (unit) { 411a55ab7c4SJin Yao if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) 412fedb2b51SAndi Kleen return -1; 413fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 414fedb2b51SAndi Kleen } 415fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 4160c24d6fbSThomas Richter alias->str = strdup(newval); 41732705de7SJin Yao alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; 418f2361024SAndi Kleen 419a7f6c8c8SJin Yao if (deprecated) 420a7f6c8c8SJin Yao alias->deprecated = true; 421a7f6c8c8SJin Yao 4226dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 423a6146d50SZheng Yan list_add_tail(&alias->list, list); 424410136f5SStephane Eranian 425a6146d50SZheng Yan return 0; 426a6146d50SZheng Yan } 427a6146d50SZheng Yan 42870c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 42970c646e0SSukadev Bhattiprolu { 43070c646e0SSukadev Bhattiprolu char buf[256]; 43170c646e0SSukadev Bhattiprolu int ret; 43270c646e0SSukadev Bhattiprolu 43370c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 43470c646e0SSukadev Bhattiprolu if (ret == 0) 43570c646e0SSukadev Bhattiprolu return -EINVAL; 43670c646e0SSukadev Bhattiprolu 43770c646e0SSukadev Bhattiprolu buf[ret] = 0; 43870c646e0SSukadev Bhattiprolu 439ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 44013c230abSArnaldo Carvalho de Melo strim(buf); 441ea23ac73SThomas Richter 442eab35953SJin Yao return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL); 44370c646e0SSukadev Bhattiprolu } 44470c646e0SSukadev Bhattiprolu 44546441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 44646441bdcSMatt Fleming { 44746441bdcSMatt Fleming size_t len; 44846441bdcSMatt Fleming 44946441bdcSMatt Fleming len = strlen(name); 45046441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 45146441bdcSMatt Fleming return true; 45246441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 45346441bdcSMatt Fleming return true; 454044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 455044330c1SMatt Fleming return true; 4561d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4571d9e446bSJiri Olsa return true; 45846441bdcSMatt Fleming 45946441bdcSMatt Fleming return false; 46046441bdcSMatt Fleming } 46146441bdcSMatt Fleming 462a6146d50SZheng Yan /* 463a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 464a6146d50SZheng Yan * specified in 'dir' parameter. 465a6146d50SZheng Yan */ 466a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 467a6146d50SZheng Yan { 468a6146d50SZheng Yan struct dirent *evt_ent; 469a6146d50SZheng Yan DIR *event_dir; 470a6146d50SZheng Yan 471a6146d50SZheng Yan event_dir = opendir(dir); 472a6146d50SZheng Yan if (!event_dir) 473a6146d50SZheng Yan return -EINVAL; 474a6146d50SZheng Yan 475940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 476a6146d50SZheng Yan char path[PATH_MAX]; 477a6146d50SZheng Yan char *name = evt_ent->d_name; 478a6146d50SZheng Yan FILE *file; 479a6146d50SZheng Yan 480a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 481a6146d50SZheng Yan continue; 482a6146d50SZheng Yan 483410136f5SStephane Eranian /* 48446441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 485410136f5SStephane Eranian */ 48646441bdcSMatt Fleming if (pmu_alias_info_file(name)) 487410136f5SStephane Eranian continue; 488410136f5SStephane Eranian 48977f18153SJiri Olsa scnprintf(path, PATH_MAX, "%s/%s", dir, name); 490a6146d50SZheng Yan 491a6146d50SZheng Yan file = fopen(path, "r"); 492940db6dcSAndi Kleen if (!file) { 493940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 494940db6dcSAndi Kleen continue; 495940db6dcSAndi Kleen } 496410136f5SStephane Eranian 497940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 498940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 499a6146d50SZheng Yan fclose(file); 500a6146d50SZheng Yan } 501a6146d50SZheng Yan 502a6146d50SZheng Yan closedir(event_dir); 503940db6dcSAndi Kleen return 0; 504a6146d50SZheng Yan } 505a6146d50SZheng Yan 506a6146d50SZheng Yan /* 507a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 508a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 509a6146d50SZheng Yan */ 510b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 511a6146d50SZheng Yan { 512a6146d50SZheng Yan char path[PATH_MAX]; 513a6146d50SZheng Yan 514f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "events")) 515a6146d50SZheng Yan return -1; 516a6146d50SZheng Yan 517d9664582SAndi Kleen if (!file_available(path)) 518d9664582SAndi Kleen return 0; 519a6146d50SZheng Yan 520a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 521a6146d50SZheng Yan return -1; 522a6146d50SZheng Yan 523a6146d50SZheng Yan return 0; 524a6146d50SZheng Yan } 525a6146d50SZheng Yan 5265c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 527a6146d50SZheng Yan struct list_head *terms) 528a6146d50SZheng Yan { 5297c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 530a6146d50SZheng Yan LIST_HEAD(list); 531a6146d50SZheng Yan int ret; 532a6146d50SZheng Yan 533a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5347c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 535a6146d50SZheng Yan if (ret) { 536682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 537a6146d50SZheng Yan return ret; 538a6146d50SZheng Yan } 539c2f1ceadSAndi Kleen /* 540c2f1ceadSAndi Kleen * Weak terms don't override command line options, 541c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 542c2f1ceadSAndi Kleen */ 543c2f1ceadSAndi Kleen cloned->weak = true; 5447c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 545a6146d50SZheng Yan } 546a6146d50SZheng Yan list_splice(&list, terms); 547a6146d50SZheng Yan return 0; 548a6146d50SZheng Yan } 549a6146d50SZheng Yan 55050a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 55150a9667cSRobert Richter static void pmu_read_sysfs(void) 55250a9667cSRobert Richter { 55350a9667cSRobert Richter char path[PATH_MAX]; 55450a9667cSRobert Richter DIR *dir; 55550a9667cSRobert Richter struct dirent *dent; 55650a9667cSRobert Richter 557f8ad6018SJames Clark if (!perf_pmu__event_source_devices_scnprintf(path, sizeof(path))) 55850a9667cSRobert Richter return; 55950a9667cSRobert Richter 56050a9667cSRobert Richter dir = opendir(path); 56150a9667cSRobert Richter if (!dir) 56250a9667cSRobert Richter return; 56350a9667cSRobert Richter 56450a9667cSRobert Richter while ((dent = readdir(dir))) { 56550a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 56650a9667cSRobert Richter continue; 56750a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 56850a9667cSRobert Richter perf_pmu__find(dent->d_name); 56950a9667cSRobert Richter } 57050a9667cSRobert Richter 57150a9667cSRobert Richter closedir(dir); 57250a9667cSRobert Richter } 57350a9667cSRobert Richter 57466ec1191SMark Rutland /* 57566ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 57666ec1191SMark Rutland * may have a "cpus" file. 57766ec1191SMark Rutland */ 578f854839bSJiri Olsa static struct perf_cpu_map *pmu_cpumask(const char *name) 5797ae92e74SYan, Zheng { 580f854839bSJiri Olsa struct perf_cpu_map *cpus; 5817e3fcffeSMark Rutland const char *templates[] = { 582d50a79cdSJames Clark "cpumask", 583d50a79cdSJames Clark "cpus", 5847e3fcffeSMark Rutland NULL 5857e3fcffeSMark Rutland }; 5867e3fcffeSMark Rutland const char **template; 587d50a79cdSJames Clark char pmu_name[PATH_MAX]; 588d50a79cdSJames Clark struct perf_pmu pmu = {.name = pmu_name}; 589d50a79cdSJames Clark FILE *file; 5907ae92e74SYan, Zheng 591d50a79cdSJames Clark strlcpy(pmu_name, name, sizeof(pmu_name)); 5927e3fcffeSMark Rutland for (template = templates; *template; template++) { 593d50a79cdSJames Clark file = perf_pmu__open_file(&pmu, *template); 594d50a79cdSJames Clark if (!file) 595d50a79cdSJames Clark continue; 596d50a79cdSJames Clark cpus = perf_cpu_map__read(file); 59766ec1191SMark Rutland if (cpus) 59866ec1191SMark Rutland return cpus; 5997e3fcffeSMark Rutland } 6007ae92e74SYan, Zheng 6017ae92e74SYan, Zheng return NULL; 60266ec1191SMark Rutland } 6037ae92e74SYan, Zheng 60466ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 60566ec1191SMark Rutland { 60666ec1191SMark Rutland char path[PATH_MAX]; 6077ae92e74SYan, Zheng 60844462430SJin Yao if (perf_pmu__hybrid_mounted(name)) 60944462430SJin Yao return false; 61044462430SJin Yao 611d50a79cdSJames Clark perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpumask"); 612d9664582SAndi Kleen return file_available(path); 6137ae92e74SYan, Zheng } 6147ae92e74SYan, Zheng 61551d54847SJohn Garry static char *pmu_id(const char *name) 61651d54847SJohn Garry { 61751d54847SJohn Garry char path[PATH_MAX], *str; 61851d54847SJohn Garry size_t len; 61951d54847SJohn Garry 6205f2c8efaSJames Clark perf_pmu__pathname_scnprintf(path, sizeof(path), name, "identifier"); 62151d54847SJohn Garry 6225f2c8efaSJames Clark if (filename__read_str(path, &str, &len) < 0) 62351d54847SJohn Garry return NULL; 62451d54847SJohn Garry 62551d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 62651d54847SJohn Garry 62751d54847SJohn Garry return str; 62851d54847SJohn Garry } 62951d54847SJohn Garry 630933f82ffSSukadev Bhattiprolu /* 63114b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 632292c34c1SKan Liang * platforms. 633292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 63414b22ae0SGanapatrao Kulkarni */ 635292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 63614b22ae0SGanapatrao Kulkarni { 63714b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 63814b22ae0SGanapatrao Kulkarni 639f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), name, "cpus")) 64014b22ae0SGanapatrao Kulkarni return 0; 641d9664582SAndi Kleen return file_available(path); 64214b22ae0SGanapatrao Kulkarni } 64314b22ae0SGanapatrao Kulkarni 64429be2fe0SIan Rogers char *perf_pmu__getcpuid(struct perf_pmu *pmu) 645d77ade9fSAndi Kleen { 646d77ade9fSAndi Kleen char *cpuid; 647d77ade9fSAndi Kleen static bool printed; 648d77ade9fSAndi Kleen 649d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 650d77ade9fSAndi Kleen if (cpuid) 651d77ade9fSAndi Kleen cpuid = strdup(cpuid); 652d77ade9fSAndi Kleen if (!cpuid) 65354e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 654d77ade9fSAndi Kleen if (!cpuid) 655d77ade9fSAndi Kleen return NULL; 656d77ade9fSAndi Kleen 657d77ade9fSAndi Kleen if (!printed) { 658d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 659d77ade9fSAndi Kleen printed = true; 660d77ade9fSAndi Kleen } 661d77ade9fSAndi Kleen return cpuid; 662d77ade9fSAndi Kleen } 663d77ade9fSAndi Kleen 6641ba3752aSIan Rogers __weak const struct pmu_events_table *pmu_events_table__find(void) 665e126bef5SJohn Garry { 666eeac7730SIan Rogers return perf_pmu__find_table(NULL); 667e126bef5SJohn Garry } 668e126bef5SJohn Garry 669c07d5c92SJohn Garry /* 670c07d5c92SJohn Garry * Suffix must be in form tok_{digits}, or tok{digits}, or same as pmu_name 671c07d5c92SJohn Garry * to be valid. 672c07d5c92SJohn Garry */ 673c07d5c92SJohn Garry static bool perf_pmu__valid_suffix(const char *pmu_name, char *tok) 674c47a5599SJin Yao { 675c07d5c92SJohn Garry const char *p; 676c47a5599SJin Yao 677c47a5599SJin Yao if (strncmp(pmu_name, tok, strlen(tok))) 678c47a5599SJin Yao return false; 679c47a5599SJin Yao 680c47a5599SJin Yao p = pmu_name + strlen(tok); 681c47a5599SJin Yao if (*p == 0) 682c47a5599SJin Yao return true; 683c47a5599SJin Yao 684c07d5c92SJohn Garry if (*p == '_') 685c47a5599SJin Yao ++p; 686c07d5c92SJohn Garry 687c07d5c92SJohn Garry /* Ensure we end in a number */ 688c07d5c92SJohn Garry while (1) { 689c07d5c92SJohn Garry if (!isdigit(*p)) 690c47a5599SJin Yao return false; 691c07d5c92SJohn Garry if (*(++p) == 0) 692c07d5c92SJohn Garry break; 693c07d5c92SJohn Garry } 694c47a5599SJin Yao 695c47a5599SJin Yao return true; 696c47a5599SJin Yao } 697c47a5599SJin Yao 6985b9a5000SJohn Garry bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 699730670b1SJohn Garry { 700730670b1SJohn Garry char *tmp = NULL, *tok, *str; 701730670b1SJohn Garry bool res; 702730670b1SJohn Garry 703730670b1SJohn Garry str = strdup(pmu_name); 704730670b1SJohn Garry if (!str) 705730670b1SJohn Garry return false; 706730670b1SJohn Garry 707730670b1SJohn Garry /* 708730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 709730670b1SJohn Garry */ 710730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 711730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 712730670b1SJohn Garry res = false; 713730670b1SJohn Garry goto out; 714730670b1SJohn Garry } 715730670b1SJohn Garry 716730670b1SJohn Garry /* 717730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 718730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 719730670b1SJohn Garry * 720730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 721730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 722730670b1SJohn Garry * "pmunameY". 723730670b1SJohn Garry */ 724c07d5c92SJohn Garry while (1) { 725c07d5c92SJohn Garry char *next_tok = strtok_r(NULL, ",", &tmp); 726c07d5c92SJohn Garry 727730670b1SJohn Garry name = strstr(name, tok); 728c07d5c92SJohn Garry if (!name || 729c07d5c92SJohn Garry (!next_tok && !perf_pmu__valid_suffix(name, tok))) { 730730670b1SJohn Garry res = false; 731730670b1SJohn Garry goto out; 732730670b1SJohn Garry } 733c07d5c92SJohn Garry if (!next_tok) 734c07d5c92SJohn Garry break; 735c07d5c92SJohn Garry tok = next_tok; 736c07d5c92SJohn Garry name += strlen(tok); 737730670b1SJohn Garry } 738730670b1SJohn Garry 739730670b1SJohn Garry res = true; 740730670b1SJohn Garry out: 741730670b1SJohn Garry free(str); 742730670b1SJohn Garry return res; 743730670b1SJohn Garry } 744730670b1SJohn Garry 745660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data { 746660842e4SIan Rogers struct list_head *head; 747660842e4SIan Rogers const char *name; 748660842e4SIan Rogers const char *cpu_name; 749660842e4SIan Rogers struct perf_pmu *pmu; 750660842e4SIan Rogers }; 751660842e4SIan Rogers 752660842e4SIan Rogers static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, 7531ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 754660842e4SIan Rogers void *vdata) 755660842e4SIan Rogers { 756660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data *data = vdata; 757660842e4SIan Rogers const char *pname = pe->pmu ? pe->pmu : data->cpu_name; 758660842e4SIan Rogers 759660842e4SIan Rogers if (!pe->name) 760660842e4SIan Rogers return 0; 761660842e4SIan Rogers 762660842e4SIan Rogers if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name)) 763660842e4SIan Rogers goto new_alias; 764660842e4SIan Rogers 765660842e4SIan Rogers if (strcmp(pname, data->name)) 766660842e4SIan Rogers return 0; 767660842e4SIan Rogers 768660842e4SIan Rogers new_alias: 769660842e4SIan Rogers /* need type casts to override 'const' */ 770660842e4SIan Rogers __perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc, 771660842e4SIan Rogers (char *)pe->event, pe); 772660842e4SIan Rogers return 0; 773660842e4SIan Rogers } 774660842e4SIan Rogers 775933f82ffSSukadev Bhattiprolu /* 776933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 777933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 778933f82ffSSukadev Bhattiprolu * as aliases. 779933f82ffSSukadev Bhattiprolu */ 780eeac7730SIan Rogers void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu, 7811ba3752aSIan Rogers const struct pmu_events_table *table) 782933f82ffSSukadev Bhattiprolu { 783660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data data = { 784660842e4SIan Rogers .head = head, 785660842e4SIan Rogers .name = pmu->name, 786660842e4SIan Rogers .cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu", 787660842e4SIan Rogers .pmu = pmu, 788660842e4SIan Rogers }; 789fedb2b51SAndi Kleen 790660842e4SIan Rogers pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data); 791933f82ffSSukadev Bhattiprolu } 792933f82ffSSukadev Bhattiprolu 793e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 794e45ad701SJohn Garry { 7951ba3752aSIan Rogers const struct pmu_events_table *table; 796e45ad701SJohn Garry 797eeac7730SIan Rogers table = perf_pmu__find_table(pmu); 798eeac7730SIan Rogers if (!table) 799e45ad701SJohn Garry return; 800e45ad701SJohn Garry 801eeac7730SIan Rogers pmu_add_cpu_aliases_table(head, pmu, table); 802e45ad701SJohn Garry } 803e45ad701SJohn Garry 8044513c719SJohn Garry struct pmu_sys_event_iter_data { 8054513c719SJohn Garry struct list_head *head; 8064513c719SJohn Garry struct perf_pmu *pmu; 8074513c719SJohn Garry }; 8084513c719SJohn Garry 80929be2fe0SIan Rogers static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, 8101ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 81129be2fe0SIan Rogers void *data) 8124513c719SJohn Garry { 8134513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8144513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8154513c719SJohn Garry 8164513c719SJohn Garry if (!pe->name) { 8174513c719SJohn Garry if (pe->metric_group || pe->metric_name) 8184513c719SJohn Garry return 0; 8194513c719SJohn Garry return -EINVAL; 8204513c719SJohn Garry } 8214513c719SJohn Garry 8224513c719SJohn Garry if (!pe->compat || !pe->pmu) 8234513c719SJohn Garry return 0; 8244513c719SJohn Garry 8254513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8264513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 8274513c719SJohn Garry __perf_pmu__new_alias(idata->head, NULL, 8284513c719SJohn Garry (char *)pe->name, 8294513c719SJohn Garry (char *)pe->desc, 8304513c719SJohn Garry (char *)pe->event, 831eab35953SJin Yao pe); 8324513c719SJohn Garry } 8334513c719SJohn Garry 8344513c719SJohn Garry return 0; 8354513c719SJohn Garry } 8364513c719SJohn Garry 837e199f47fSJohn Garry void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 8384513c719SJohn Garry { 8394513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 8404513c719SJohn Garry .head = head, 8414513c719SJohn Garry .pmu = pmu, 8424513c719SJohn Garry }; 8434513c719SJohn Garry 8444513c719SJohn Garry if (!pmu->id) 8454513c719SJohn Garry return; 8464513c719SJohn Garry 8474513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 8484513c719SJohn Garry } 8494513c719SJohn Garry 850c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 851dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 852dc0a6202SAdrian Hunter { 853dc0a6202SAdrian Hunter return NULL; 854dc0a6202SAdrian Hunter } 855dc0a6202SAdrian Hunter 85613d60ba0SKan Liang char * __weak 85713d60ba0SKan Liang pmu_find_real_name(const char *name) 85813d60ba0SKan Liang { 85913d60ba0SKan Liang return (char *)name; 86013d60ba0SKan Liang } 86113d60ba0SKan Liang 86213d60ba0SKan Liang char * __weak 86313d60ba0SKan Liang pmu_find_alias_name(const char *name __maybe_unused) 86413d60ba0SKan Liang { 86513d60ba0SKan Liang return NULL; 86613d60ba0SKan Liang } 86713d60ba0SKan Liang 8685f2c8efaSJames Clark static int pmu_max_precise(struct perf_pmu *pmu) 86990a86bdeSJiri Olsa { 87090a86bdeSJiri Olsa int max_precise = -1; 87190a86bdeSJiri Olsa 8725f2c8efaSJames Clark perf_pmu__scan_file(pmu, "caps/max_precise", "%d", &max_precise); 87390a86bdeSJiri Olsa return max_precise; 87490a86bdeSJiri Olsa } 87590a86bdeSJiri Olsa 87613d60ba0SKan Liang static struct perf_pmu *pmu_lookup(const char *lookup_name) 877cd82a32eSJiri Olsa { 878cd82a32eSJiri Olsa struct perf_pmu *pmu; 879cd82a32eSJiri Olsa LIST_HEAD(format); 880a6146d50SZheng Yan LIST_HEAD(aliases); 881cd82a32eSJiri Olsa __u32 type; 88213d60ba0SKan Liang char *name = pmu_find_real_name(lookup_name); 88349afa7f6SJin Yao bool is_hybrid = perf_pmu__hybrid_mounted(name); 88413d60ba0SKan Liang char *alias_name; 88549afa7f6SJin Yao 88649afa7f6SJin Yao /* 88749afa7f6SJin Yao * Check pmu name for hybrid and the pmu may be invalid in sysfs 88849afa7f6SJin Yao */ 88949afa7f6SJin Yao if (!strncmp(name, "cpu_", 4) && !is_hybrid) 89049afa7f6SJin Yao return NULL; 891cd82a32eSJiri Olsa 892cd82a32eSJiri Olsa /* 893cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 894cd82a32eSJiri Olsa * type value and format definitions. Load both right 895cd82a32eSJiri Olsa * now. 896cd82a32eSJiri Olsa */ 897cd82a32eSJiri Olsa if (pmu_format(name, &format)) 898cd82a32eSJiri Olsa return NULL; 899cd82a32eSJiri Olsa 90015b22ed3SAndi Kleen /* 901f8ad6018SJames Clark * Check the aliases first to avoid unnecessary work. 90215b22ed3SAndi Kleen */ 9033fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 9043fded963SJiri Olsa return NULL; 9053fded963SJiri Olsa 906cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 907cd82a32eSJiri Olsa if (!pmu) 908cd82a32eSJiri Olsa return NULL; 909cd82a32eSJiri Olsa 9107ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 91154e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 912f8ad6018SJames Clark 91313d60ba0SKan Liang if (!pmu->name) 91413d60ba0SKan Liang goto err; 91513d60ba0SKan Liang 916f8ad6018SJames Clark /* Read type, and ensure that type value is successfully assigned (return 1) */ 917f8ad6018SJames Clark if (perf_pmu__scan_file(pmu, "type", "%u", &type) != 1) 918f8ad6018SJames Clark goto err; 919f8ad6018SJames Clark 92013d60ba0SKan Liang alias_name = pmu_find_alias_name(name); 92113d60ba0SKan Liang if (alias_name) { 92213d60ba0SKan Liang pmu->alias_name = strdup(alias_name); 92313d60ba0SKan Liang if (!pmu->alias_name) 92413d60ba0SKan Liang goto err; 92513d60ba0SKan Liang } 92613d60ba0SKan Liang 92754e32dc0SGanapatrao Kulkarni pmu->type = type; 92866ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 92951d54847SJohn Garry if (pmu->is_uncore) 93051d54847SJohn Garry pmu->id = pmu_id(name); 9315f2c8efaSJames Clark pmu->max_precise = pmu_max_precise(pmu); 93254e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 9334513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 93466ec1191SMark Rutland 935cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 936a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 9379fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 938cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 939a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 9409bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 941dc0a6202SAdrian Hunter 942e5f4afbeSIan Rogers if (is_hybrid) 94344462430SJin Yao list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus); 94444462430SJin Yao 945dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 946dc0a6202SAdrian Hunter 947cd82a32eSJiri Olsa return pmu; 94813d60ba0SKan Liang err: 94913d60ba0SKan Liang if (pmu->name) 95013d60ba0SKan Liang free(pmu->name); 95113d60ba0SKan Liang free(pmu); 95213d60ba0SKan Liang return NULL; 953cd82a32eSJiri Olsa } 954cd82a32eSJiri Olsa 955e552b7beSRob Herring void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) 956e552b7beSRob Herring { 957e552b7beSRob Herring struct perf_pmu_format *format; 958e552b7beSRob Herring 959e552b7beSRob Herring /* fake pmu doesn't have format list */ 960e552b7beSRob Herring if (pmu == &perf_pmu__fake) 961e552b7beSRob Herring return; 962e552b7beSRob Herring 963e552b7beSRob Herring list_for_each_entry(format, &pmu->format, list) 964e552b7beSRob Herring if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) { 965e552b7beSRob Herring pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'" 966e552b7beSRob Herring "which is not supported by this version of perf!\n", 967e552b7beSRob Herring pmu->name, format->name, format->value); 968e552b7beSRob Herring return; 969e552b7beSRob Herring } 970e552b7beSRob Herring } 971e552b7beSRob Herring 972b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 973cd82a32eSJiri Olsa { 974cd82a32eSJiri Olsa struct perf_pmu *pmu; 975cd82a32eSJiri Olsa 97613d60ba0SKan Liang list_for_each_entry(pmu, &pmus, list) { 97713d60ba0SKan Liang if (!strcmp(pmu->name, name) || 97813d60ba0SKan Liang (pmu->alias_name && !strcmp(pmu->alias_name, name))) 979cd82a32eSJiri Olsa return pmu; 98013d60ba0SKan Liang } 981cd82a32eSJiri Olsa 982cd82a32eSJiri Olsa return NULL; 983cd82a32eSJiri Olsa } 984cd82a32eSJiri Olsa 9853a50dc76SStephane Eranian struct perf_pmu *perf_pmu__find_by_type(unsigned int type) 9863a50dc76SStephane Eranian { 9873a50dc76SStephane Eranian struct perf_pmu *pmu; 9883a50dc76SStephane Eranian 9893a50dc76SStephane Eranian list_for_each_entry(pmu, &pmus, list) 9903a50dc76SStephane Eranian if (pmu->type == type) 9913a50dc76SStephane Eranian return pmu; 9923a50dc76SStephane Eranian 9933a50dc76SStephane Eranian return NULL; 9943a50dc76SStephane Eranian } 9953a50dc76SStephane Eranian 99650a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 99750a9667cSRobert Richter { 99850a9667cSRobert Richter /* 99950a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 100050a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 100150a9667cSRobert Richter */ 100250a9667cSRobert Richter if (!pmu) { 100350a9667cSRobert Richter pmu_read_sysfs(); 100450a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 100550a9667cSRobert Richter } 100650a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 100750a9667cSRobert Richter return pmu; 100850a9667cSRobert Richter return NULL; 100950a9667cSRobert Richter } 101050a9667cSRobert Richter 1011e76026bdSArnaldo Carvalho de Melo struct perf_pmu *evsel__find_pmu(struct evsel *evsel) 1012e12ee9f7SAdrian Hunter { 1013e12ee9f7SAdrian Hunter struct perf_pmu *pmu = NULL; 1014e12ee9f7SAdrian Hunter 1015f7400262SNamhyung Kim if (evsel->pmu) 1016f7400262SNamhyung Kim return evsel->pmu; 1017f7400262SNamhyung Kim 1018e12ee9f7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1019e12ee9f7SAdrian Hunter if (pmu->type == evsel->core.attr.type) 1020e12ee9f7SAdrian Hunter break; 1021e12ee9f7SAdrian Hunter } 1022e12ee9f7SAdrian Hunter 1023f7400262SNamhyung Kim evsel->pmu = pmu; 1024e12ee9f7SAdrian Hunter return pmu; 1025e12ee9f7SAdrian Hunter } 1026e12ee9f7SAdrian Hunter 102739453ed5SArnaldo Carvalho de Melo bool evsel__is_aux_event(struct evsel *evsel) 1028e12ee9f7SAdrian Hunter { 1029e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 1030e12ee9f7SAdrian Hunter 1031e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 1032e12ee9f7SAdrian Hunter } 1033e12ee9f7SAdrian Hunter 1034b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 1035cd82a32eSJiri Olsa { 1036cd82a32eSJiri Olsa struct perf_pmu *pmu; 1037cd82a32eSJiri Olsa 1038cd82a32eSJiri Olsa /* 1039cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 1040cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 1041cd82a32eSJiri Olsa * the pmu format definitions. 1042cd82a32eSJiri Olsa */ 1043cd82a32eSJiri Olsa pmu = pmu_find(name); 1044cd82a32eSJiri Olsa if (pmu) 1045cd82a32eSJiri Olsa return pmu; 1046cd82a32eSJiri Olsa 1047cd82a32eSJiri Olsa return pmu_lookup(name); 1048cd82a32eSJiri Olsa } 1049cd82a32eSJiri Olsa 10505c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 105109ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 1052cd82a32eSJiri Olsa { 10535c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1054cd82a32eSJiri Olsa 1055cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 1056cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 1057cd82a32eSJiri Olsa return format; 1058cd82a32eSJiri Olsa 1059cd82a32eSJiri Olsa return NULL; 1060cd82a32eSJiri Olsa } 1061cd82a32eSJiri Olsa 106209ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 106309ff6071SAdrian Hunter { 106409ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 106509ff6071SAdrian Hunter __u64 bits = 0; 106609ff6071SAdrian Hunter int fbit; 106709ff6071SAdrian Hunter 106809ff6071SAdrian Hunter if (!format) 106909ff6071SAdrian Hunter return 0; 107009ff6071SAdrian Hunter 107109ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 107209ff6071SAdrian Hunter bits |= 1ULL << fbit; 107309ff6071SAdrian Hunter 107409ff6071SAdrian Hunter return bits; 107509ff6071SAdrian Hunter } 107609ff6071SAdrian Hunter 1077a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1078a1ac7de6SAdrian Hunter { 1079a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1080a1ac7de6SAdrian Hunter 1081a1ac7de6SAdrian Hunter if (!format) 1082a1ac7de6SAdrian Hunter return -1; 1083a1ac7de6SAdrian Hunter 1084a1ac7de6SAdrian Hunter return format->value; 1085a1ac7de6SAdrian Hunter } 1086a1ac7de6SAdrian Hunter 1087cd82a32eSJiri Olsa /* 1088dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 10894d39c89fSIngo Molnar * and unformatted value (value parameter). 1090cd82a32eSJiri Olsa */ 1091dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1092dc0a6202SAdrian Hunter bool zero) 1093cd82a32eSJiri Olsa { 1094cd82a32eSJiri Olsa unsigned long fbit, vbit; 1095cd82a32eSJiri Olsa 1096cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1097cd82a32eSJiri Olsa 1098cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1099cd82a32eSJiri Olsa continue; 1100cd82a32eSJiri Olsa 1101dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1102dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1103dc0a6202SAdrian Hunter else if (zero) 1104dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1105cd82a32eSJiri Olsa } 1106cd82a32eSJiri Olsa } 1107cd82a32eSJiri Olsa 11080efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 11090efe6b67SAdrian Hunter { 11101b9caa10SJiri Olsa int w; 11110efe6b67SAdrian Hunter 11121b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 11131b9caa10SJiri Olsa if (!w) 11141b9caa10SJiri Olsa return 0; 11151b9caa10SJiri Olsa if (w < 64) 11161b9caa10SJiri Olsa return (1ULL << w) - 1; 11171b9caa10SJiri Olsa return -1; 11180efe6b67SAdrian Hunter } 11190efe6b67SAdrian Hunter 1120cd82a32eSJiri Olsa /* 1121688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1122688d4dfcSCody P Schafer * in the remaining terms. 1123688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1124688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1125688d4dfcSCody P Schafer * in a config string) later on in the term list. 1126688d4dfcSCody P Schafer */ 1127688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1128688d4dfcSCody P Schafer struct list_head *head_terms, 1129688d4dfcSCody P Schafer __u64 *value) 1130688d4dfcSCody P Schafer { 1131688d4dfcSCody P Schafer struct parse_events_term *t; 1132688d4dfcSCody P Schafer 1133688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 11342a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 11352a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1136688d4dfcSCody P Schafer t->used = true; 1137688d4dfcSCody P Schafer *value = t->val.num; 1138688d4dfcSCody P Schafer return 0; 1139688d4dfcSCody P Schafer } 1140688d4dfcSCody P Schafer } 1141688d4dfcSCody P Schafer 1142bb963e16SNamhyung Kim if (verbose > 0) 1143688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1144688d4dfcSCody P Schafer 1145688d4dfcSCody P Schafer return -1; 1146688d4dfcSCody P Schafer } 1147688d4dfcSCody P Schafer 1148ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1149e64b020bSJiri Olsa { 1150e64b020bSJiri Olsa struct perf_pmu_format *format; 115111db4e29SMasami Hiramatsu char *str = NULL; 115211db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1153f1417ceaSXin Gao unsigned int i = 0; 1154e64b020bSJiri Olsa 1155ffeb883eSHe Kuang if (!formats) 1156e64b020bSJiri Olsa return NULL; 1157e64b020bSJiri Olsa 1158e64b020bSJiri Olsa /* sysfs exported terms */ 1159ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 116011db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 116111db4e29SMasami Hiramatsu goto error; 1162e64b020bSJiri Olsa 1163ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 116411db4e29SMasami Hiramatsu error: 1165ffeb883eSHe Kuang strbuf_release(&buf); 1166e64b020bSJiri Olsa 1167e64b020bSJiri Olsa return str; 1168e64b020bSJiri Olsa } 1169e64b020bSJiri Olsa 1170688d4dfcSCody P Schafer /* 1171cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 117288aca8d9SCody P Schafer * user input data - term parameter. 1173cd82a32eSJiri Olsa */ 11744ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 11754ac22b48SIan Rogers struct list_head *formats, 1176cd82a32eSJiri Olsa struct perf_event_attr *attr, 1177dc0a6202SAdrian Hunter struct parse_events_term *term, 1178688d4dfcSCody P Schafer struct list_head *head_terms, 1179e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1180cd82a32eSJiri Olsa { 11815c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1182cd82a32eSJiri Olsa __u64 *vp; 11830efe6b67SAdrian Hunter __u64 val, max_val; 1184cd82a32eSJiri Olsa 1185cd82a32eSJiri Olsa /* 1186688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1187688d4dfcSCody P Schafer * skip it in normal eval. 1188688d4dfcSCody P Schafer */ 1189688d4dfcSCody P Schafer if (term->used) 1190688d4dfcSCody P Schafer return 0; 1191688d4dfcSCody P Schafer 1192688d4dfcSCody P Schafer /* 1193cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1194cd82a32eSJiri Olsa * to be done for them. 1195cd82a32eSJiri Olsa */ 1196cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1197cd82a32eSJiri Olsa return 0; 1198cd82a32eSJiri Olsa 1199cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1200688d4dfcSCody P Schafer if (!format) { 1201ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 12024ac22b48SIan Rogers char *unknown_term; 12034ac22b48SIan Rogers char *help_msg; 1204ffeb883eSHe Kuang 12054ac22b48SIan Rogers if (asprintf(&unknown_term, 12064ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 12074ac22b48SIan Rogers term->config, pmu_name) < 0) 12084ac22b48SIan Rogers unknown_term = NULL; 12094ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 12104ac22b48SIan Rogers if (err) { 12116c191289SIan Rogers parse_events_error__handle(err, term->err_term, 12124ac22b48SIan Rogers unknown_term, 12134ac22b48SIan Rogers help_msg); 12144ac22b48SIan Rogers } else { 12154ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 12164ac22b48SIan Rogers free(unknown_term); 1217e64b020bSJiri Olsa } 12184ac22b48SIan Rogers free(pmu_term); 1219cd82a32eSJiri Olsa return -EINVAL; 1220688d4dfcSCody P Schafer } 1221cd82a32eSJiri Olsa 1222cd82a32eSJiri Olsa switch (format->value) { 1223cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1224cd82a32eSJiri Olsa vp = &attr->config; 1225cd82a32eSJiri Olsa break; 1226cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1227cd82a32eSJiri Olsa vp = &attr->config1; 1228cd82a32eSJiri Olsa break; 1229cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1230cd82a32eSJiri Olsa vp = &attr->config2; 1231cd82a32eSJiri Olsa break; 1232cd82a32eSJiri Olsa default: 1233cd82a32eSJiri Olsa return -EINVAL; 1234cd82a32eSJiri Olsa } 1235cd82a32eSJiri Olsa 123616fa7e82SJiri Olsa /* 1237688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1238688d4dfcSCody P Schafer * using event parameters. 123916fa7e82SJiri Olsa */ 124099e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 124199e7138eSJiri Olsa if (term->no_value && 124299e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 124399e7138eSJiri Olsa if (err) { 12446c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1245448d732cSIan Rogers strdup("no value assigned for term"), 1246448d732cSIan Rogers NULL); 124799e7138eSJiri Olsa } 124899e7138eSJiri Olsa return -EINVAL; 124999e7138eSJiri Olsa } 125099e7138eSJiri Olsa 1251688d4dfcSCody P Schafer val = term->val.num; 125299e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1253688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1254bb963e16SNamhyung Kim if (verbose > 0) { 1255688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1256688d4dfcSCody P Schafer term->config, term->val.str); 1257e64b020bSJiri Olsa } 1258e64b020bSJiri Olsa if (err) { 12596c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1260448d732cSIan Rogers strdup("expected numeric value"), 1261448d732cSIan Rogers NULL); 1262e64b020bSJiri Olsa } 1263688d4dfcSCody P Schafer return -EINVAL; 1264688d4dfcSCody P Schafer } 1265688d4dfcSCody P Schafer 1266688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1267688d4dfcSCody P Schafer return -EINVAL; 1268688d4dfcSCody P Schafer } else 1269688d4dfcSCody P Schafer return -EINVAL; 1270688d4dfcSCody P Schafer 12710efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 12720efe6b67SAdrian Hunter if (val > max_val) { 12730efe6b67SAdrian Hunter if (err) { 1274448d732cSIan Rogers char *err_str; 1275448d732cSIan Rogers 12766c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1277448d732cSIan Rogers asprintf(&err_str, 12780efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1279448d732cSIan Rogers (unsigned long long)max_val) < 0 1280448d732cSIan Rogers ? strdup("value too big for format") 1281448d732cSIan Rogers : err_str, 1282448d732cSIan Rogers NULL); 12830efe6b67SAdrian Hunter return -EINVAL; 12840efe6b67SAdrian Hunter } 12850efe6b67SAdrian Hunter /* 12860efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 12870efe6b67SAdrian Hunter * silently truncated. 12880efe6b67SAdrian Hunter */ 12890efe6b67SAdrian Hunter } 12900efe6b67SAdrian Hunter 1291688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1292cd82a32eSJiri Olsa return 0; 1293cd82a32eSJiri Olsa } 1294cd82a32eSJiri Olsa 12954ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1296cff7f956SJiri Olsa struct perf_event_attr *attr, 1297dc0a6202SAdrian Hunter struct list_head *head_terms, 1298e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1299cd82a32eSJiri Olsa { 13006cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1301cd82a32eSJiri Olsa 1302688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 13034ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1304e64b020bSJiri Olsa zero, err)) 1305cd82a32eSJiri Olsa return -EINVAL; 1306688d4dfcSCody P Schafer } 1307cd82a32eSJiri Olsa 1308cd82a32eSJiri Olsa return 0; 1309cd82a32eSJiri Olsa } 1310cd82a32eSJiri Olsa 1311cd82a32eSJiri Olsa /* 1312cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1313cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1314cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1315cd82a32eSJiri Olsa */ 1316cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1317e64b020bSJiri Olsa struct list_head *head_terms, 1318e64b020bSJiri Olsa struct parse_events_error *err) 1319cd82a32eSJiri Olsa { 1320dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1321dc0a6202SAdrian Hunter 1322cd82a32eSJiri Olsa attr->type = pmu->type; 13234ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 13244ac22b48SIan Rogers head_terms, zero, err); 1325cd82a32eSJiri Olsa } 1326cd82a32eSJiri Olsa 13275c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 13286cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1329a6146d50SZheng Yan { 13305c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1331a6146d50SZheng Yan char *name; 1332a6146d50SZheng Yan 1333a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1334a6146d50SZheng Yan return NULL; 1335a6146d50SZheng Yan 1336a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1337a6146d50SZheng Yan if (term->val.num != 1) 1338a6146d50SZheng Yan return NULL; 1339a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1340a6146d50SZheng Yan return NULL; 1341a6146d50SZheng Yan name = term->config; 1342a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1343a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1344a6146d50SZheng Yan return NULL; 1345a6146d50SZheng Yan name = term->val.str; 1346a6146d50SZheng Yan } else { 1347a6146d50SZheng Yan return NULL; 1348a6146d50SZheng Yan } 1349a6146d50SZheng Yan 1350a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1351a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1352a6146d50SZheng Yan return alias; 1353a6146d50SZheng Yan } 1354a6146d50SZheng Yan return NULL; 1355a6146d50SZheng Yan } 1356a6146d50SZheng Yan 1357410136f5SStephane Eranian 13581d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 13591d9e446bSJiri Olsa struct perf_pmu_info *info) 1360410136f5SStephane Eranian { 1361410136f5SStephane Eranian /* 1362410136f5SStephane Eranian * Only one term in event definition can 13631d9e446bSJiri Olsa * define unit, scale and snapshot, fail 13641d9e446bSJiri Olsa * if there's more than one. 1365410136f5SStephane Eranian */ 1366b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 13671d9e446bSJiri Olsa (info->scale && alias->scale) || 13681d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1369410136f5SStephane Eranian return -EINVAL; 1370410136f5SStephane Eranian 1371b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 13721d9e446bSJiri Olsa info->unit = alias->unit; 1373410136f5SStephane Eranian 1374410136f5SStephane Eranian if (alias->scale) 13751d9e446bSJiri Olsa info->scale = alias->scale; 13761d9e446bSJiri Olsa 13771d9e446bSJiri Olsa if (alias->snapshot) 13781d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1379410136f5SStephane Eranian 1380410136f5SStephane Eranian return 0; 1381410136f5SStephane Eranian } 1382410136f5SStephane Eranian 1383a6146d50SZheng Yan /* 1384a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1385a6146d50SZheng Yan * defined for the alias 1386a6146d50SZheng Yan */ 1387410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 138846441bdcSMatt Fleming struct perf_pmu_info *info) 1389a6146d50SZheng Yan { 13906cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 13915c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1392a6146d50SZheng Yan int ret; 1393a6146d50SZheng Yan 1394044330c1SMatt Fleming info->per_pkg = false; 1395044330c1SMatt Fleming 13968a398897SStephane Eranian /* 13978a398897SStephane Eranian * Mark unit and scale as not set 13988a398897SStephane Eranian * (different from default values, see below) 13998a398897SStephane Eranian */ 140046441bdcSMatt Fleming info->unit = NULL; 140146441bdcSMatt Fleming info->scale = 0.0; 14021d9e446bSJiri Olsa info->snapshot = false; 140337932c18SAndi Kleen info->metric_expr = NULL; 140496284814SAndi Kleen info->metric_name = NULL; 1405410136f5SStephane Eranian 1406a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1407a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1408a6146d50SZheng Yan if (!alias) 1409a6146d50SZheng Yan continue; 1410a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1411a6146d50SZheng Yan if (ret) 1412a6146d50SZheng Yan return ret; 1413410136f5SStephane Eranian 14141d9e446bSJiri Olsa ret = check_info_data(alias, info); 1415410136f5SStephane Eranian if (ret) 1416410136f5SStephane Eranian return ret; 1417410136f5SStephane Eranian 1418044330c1SMatt Fleming if (alias->per_pkg) 1419044330c1SMatt Fleming info->per_pkg = true; 142037932c18SAndi Kleen info->metric_expr = alias->metric_expr; 142196284814SAndi Kleen info->metric_name = alias->metric_name; 1422044330c1SMatt Fleming 1423e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 14241dc92556SIan Rogers parse_events_term__delete(term); 1425a6146d50SZheng Yan } 14268a398897SStephane Eranian 14278a398897SStephane Eranian /* 14288a398897SStephane Eranian * if no unit or scale found in aliases, then 14298a398897SStephane Eranian * set defaults as for evsel 14308a398897SStephane Eranian * unit cannot left to NULL 14318a398897SStephane Eranian */ 143246441bdcSMatt Fleming if (info->unit == NULL) 143346441bdcSMatt Fleming info->unit = ""; 14348a398897SStephane Eranian 143546441bdcSMatt Fleming if (info->scale == 0.0) 143646441bdcSMatt Fleming info->scale = 1.0; 14378a398897SStephane Eranian 1438a6146d50SZheng Yan return 0; 1439a6146d50SZheng Yan } 1440a6146d50SZheng Yan 1441cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1442cd82a32eSJiri Olsa int config, unsigned long *bits) 1443cd82a32eSJiri Olsa { 14445c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1445cd82a32eSJiri Olsa 1446cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1447cd82a32eSJiri Olsa if (!format) 1448cd82a32eSJiri Olsa return -ENOMEM; 1449cd82a32eSJiri Olsa 1450cd82a32eSJiri Olsa format->name = strdup(name); 1451cd82a32eSJiri Olsa format->value = config; 1452cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1453cd82a32eSJiri Olsa 1454cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1455cd82a32eSJiri Olsa return 0; 1456cd82a32eSJiri Olsa } 1457cd82a32eSJiri Olsa 1458cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1459cd82a32eSJiri Olsa { 1460cd82a32eSJiri Olsa long b; 1461cd82a32eSJiri Olsa 1462cd82a32eSJiri Olsa if (!to) 1463cd82a32eSJiri Olsa to = from; 1464cd82a32eSJiri Olsa 146515268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1466cd82a32eSJiri Olsa for (b = from; b <= to; b++) 146749bd97c2SSean Christopherson __set_bit(b, bits); 1468cd82a32eSJiri Olsa } 1469dc098b35SAndi Kleen 1470d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1471d26383dcSNamhyung Kim { 1472d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1473d26383dcSNamhyung Kim 1474d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1475d26383dcSNamhyung Kim list_del(&fmt->list); 1476d26383dcSNamhyung Kim free(fmt->name); 1477d26383dcSNamhyung Kim free(fmt); 1478d26383dcSNamhyung Kim } 1479d26383dcSNamhyung Kim } 1480d26383dcSNamhyung Kim 1481aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1482aaea3617SCody P Schafer { 1483aaea3617SCody P Schafer if (b > a) 1484aaea3617SCody P Schafer return 0; 1485aaea3617SCody P Schafer return a - b; 1486aaea3617SCody P Schafer } 1487aaea3617SCody P Schafer 1488eb2d4514SIan Rogers static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, 1489eb2d4514SIan Rogers const struct perf_pmu_alias *alias) 1490dc098b35SAndi Kleen { 1491aaea3617SCody P Schafer struct parse_events_term *term; 1492aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1493aaea3617SCody P Schafer 1494aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1495aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1496aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1497aaea3617SCody P Schafer ",%s=%s", term->config, 1498aaea3617SCody P Schafer term->val.str); 1499aaea3617SCody P Schafer } 1500aaea3617SCody P Schafer 1501aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1502aaea3617SCody P Schafer buf[used] = '/'; 1503aaea3617SCody P Schafer used++; 1504aaea3617SCody P Schafer } 1505aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1506aaea3617SCody P Schafer buf[used] = '\0'; 1507aaea3617SCody P Schafer used++; 1508aaea3617SCody P Schafer } else 1509aaea3617SCody P Schafer buf[len - 1] = '\0'; 1510aaea3617SCody P Schafer 1511dc098b35SAndi Kleen return buf; 1512dc098b35SAndi Kleen } 1513dc098b35SAndi Kleen 1514eb2d4514SIan Rogers /** Struct for ordering events as output in perf list. */ 1515dd5f1036SAndi Kleen struct sevent { 1516eb2d4514SIan Rogers /** PMU for event. */ 1517eb2d4514SIan Rogers const struct perf_pmu *pmu; 1518eb2d4514SIan Rogers /** 1519eb2d4514SIan Rogers * Optional event for name, desc, etc. If not present then this is a 1520eb2d4514SIan Rogers * selectable PMU and the event name is shown as "//". 1521eb2d4514SIan Rogers */ 1522eb2d4514SIan Rogers const struct perf_pmu_alias *event; 1523eb2d4514SIan Rogers /** Is the PMU for the CPU? */ 1524eb2d4514SIan Rogers bool is_cpu; 152508e60ed1SAndi Kleen }; 152608e60ed1SAndi Kleen 1527dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1528dc098b35SAndi Kleen { 1529dd5f1036SAndi Kleen const struct sevent *as = a; 1530dd5f1036SAndi Kleen const struct sevent *bs = b; 1531eb2d4514SIan Rogers const char *a_pmu_name, *b_pmu_name; 1532eb2d4514SIan Rogers const char *a_name = "//", *a_desc = NULL, *a_topic = ""; 1533eb2d4514SIan Rogers const char *b_name = "//", *b_desc = NULL, *b_topic = ""; 15340e0ae874SJin Yao int ret; 153508e60ed1SAndi Kleen 1536eb2d4514SIan Rogers if (as->event) { 1537eb2d4514SIan Rogers a_name = as->event->name; 1538eb2d4514SIan Rogers a_desc = as->event->desc; 1539eb2d4514SIan Rogers a_topic = as->event->topic ?: ""; 1540dd5f1036SAndi Kleen } 1541eb2d4514SIan Rogers if (bs->event) { 1542eb2d4514SIan Rogers b_name = bs->event->name; 1543eb2d4514SIan Rogers b_desc = bs->event->desc; 1544eb2d4514SIan Rogers b_topic = bs->event->topic ?: ""; 1545eb2d4514SIan Rogers } 1546eb2d4514SIan Rogers /* Put extra events last. */ 1547eb2d4514SIan Rogers if (!!a_desc != !!b_desc) 1548eb2d4514SIan Rogers return !!a_desc - !!b_desc; 1549eb2d4514SIan Rogers 1550eb2d4514SIan Rogers /* Order by topics. */ 1551eb2d4514SIan Rogers ret = strcmp(a_topic, b_topic); 1552eb2d4514SIan Rogers if (ret) 1553eb2d4514SIan Rogers return ret; 1554ce0dc7d2SJohn Garry 1555ce0dc7d2SJohn Garry /* Order CPU core events to be first */ 1556ce0dc7d2SJohn Garry if (as->is_cpu != bs->is_cpu) 1557e5c6109fSIan Rogers return as->is_cpu ? -1 : 1; 1558ce0dc7d2SJohn Garry 1559eb2d4514SIan Rogers /* Order by PMU name. */ 1560eb2d4514SIan Rogers a_pmu_name = as->pmu->name ?: ""; 1561eb2d4514SIan Rogers b_pmu_name = bs->pmu->name ?: ""; 1562eb2d4514SIan Rogers ret = strcmp(a_pmu_name, b_pmu_name); 1563eb2d4514SIan Rogers if (ret) 15640e0ae874SJin Yao return ret; 1565eb2d4514SIan Rogers 1566eb2d4514SIan Rogers /* Order by event name. */ 1567eb2d4514SIan Rogers return strcmp(a_name, b_name); 156808e60ed1SAndi Kleen } 156908e60ed1SAndi Kleen 1570d504fae9SJohn Garry bool is_pmu_core(const char *name) 1571d504fae9SJohn Garry { 1572d504fae9SJohn Garry return !strcmp(name, "cpu") || is_arm_pmu_core(name); 1573d504fae9SJohn Garry } 1574d504fae9SJohn Garry 1575e0257a01SJohn Garry static bool pmu_alias_is_duplicate(struct sevent *alias_a, 1576e0257a01SJohn Garry struct sevent *alias_b) 1577e0257a01SJohn Garry { 1578eb2d4514SIan Rogers const char *a_pmu_name, *b_pmu_name; 1579eb2d4514SIan Rogers const char *a_name = alias_a->event ? alias_a->event->name : "//"; 1580eb2d4514SIan Rogers const char *b_name = alias_b->event ? alias_b->event->name : "//"; 1581eb2d4514SIan Rogers 1582e0257a01SJohn Garry /* Different names -> never duplicates */ 1583eb2d4514SIan Rogers if (strcmp(a_name, b_name)) 1584e0257a01SJohn Garry return false; 1585e0257a01SJohn Garry 1586eb2d4514SIan Rogers /* Don't remove duplicates for different PMUs */ 1587eb2d4514SIan Rogers a_pmu_name = alias_a->pmu->name ?: ""; 1588eb2d4514SIan Rogers b_pmu_name = alias_b->pmu->name ?: ""; 1589eb2d4514SIan Rogers return strcmp(a_pmu_name, b_pmu_name) == 0; 1590e0257a01SJohn Garry } 1591e0257a01SJohn Garry 1592e5c6109fSIan Rogers void print_pmu_events(const struct print_callbacks *print_cb, void *print_state) 1593dc098b35SAndi Kleen { 1594dc098b35SAndi Kleen struct perf_pmu *pmu; 1595e5c6109fSIan Rogers struct perf_pmu_alias *event; 1596dc098b35SAndi Kleen char buf[1024]; 1597dc098b35SAndi Kleen int printed = 0; 1598dc098b35SAndi Kleen int len, j; 1599dd5f1036SAndi Kleen struct sevent *aliases; 1600dc098b35SAndi Kleen 1601dc098b35SAndi Kleen pmu = NULL; 1602dc098b35SAndi Kleen len = 0; 160342634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1604e5c6109fSIan Rogers list_for_each_entry(event, &pmu->aliases, list) 1605dc098b35SAndi Kleen len++; 160642634bc7SAdrian Hunter if (pmu->selectable) 160742634bc7SAdrian Hunter len++; 160842634bc7SAdrian Hunter } 1609dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1610eb2d4514SIan Rogers if (!aliases) { 1611eb2d4514SIan Rogers pr_err("FATAL: not enough memory to print PMU events\n"); 1612eb2d4514SIan Rogers return; 1613eb2d4514SIan Rogers } 1614dc098b35SAndi Kleen pmu = NULL; 1615dc098b35SAndi Kleen j = 0; 161642634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1617e5c6109fSIan Rogers bool is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); 1618eb2d4514SIan Rogers 1619e5c6109fSIan Rogers list_for_each_entry(event, &pmu->aliases, list) { 1620e5c6109fSIan Rogers aliases[j].event = event; 1621eb2d4514SIan Rogers aliases[j].pmu = pmu; 1622ce0dc7d2SJohn Garry aliases[j].is_cpu = is_cpu; 1623dc098b35SAndi Kleen j++; 1624dc098b35SAndi Kleen } 1625e5c6109fSIan Rogers if (pmu->selectable) { 1626eb2d4514SIan Rogers aliases[j].event = NULL; 1627eb2d4514SIan Rogers aliases[j].pmu = pmu; 1628eb2d4514SIan Rogers aliases[j].is_cpu = is_cpu; 162942634bc7SAdrian Hunter j++; 163042634bc7SAdrian Hunter } 163142634bc7SAdrian Hunter } 1632dc098b35SAndi Kleen len = j; 1633dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1634dc098b35SAndi Kleen for (j = 0; j < len; j++) { 1635e5c6109fSIan Rogers const char *name, *alias = NULL, *scale_unit = NULL, 1636e5c6109fSIan Rogers *desc = NULL, *long_desc = NULL, 1637e5c6109fSIan Rogers *encoding_desc = NULL, *topic = NULL, 1638e5c6109fSIan Rogers *metric_name = NULL, *metric_expr = NULL; 1639e5c6109fSIan Rogers bool deprecated = false; 1640e5c6109fSIan Rogers size_t buf_used; 1641eb2d4514SIan Rogers 164215b22ed3SAndi Kleen /* Skip duplicates */ 1643e0257a01SJohn Garry if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) 164415b22ed3SAndi Kleen continue; 16450e0ae874SJin Yao 1646eb2d4514SIan Rogers if (!aliases[j].event) { 1647eb2d4514SIan Rogers /* A selectable event. */ 1648e5c6109fSIan Rogers buf_used = snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name) + 1; 1649eb2d4514SIan Rogers name = buf; 1650eb2d4514SIan Rogers } else { 1651e5c6109fSIan Rogers if (aliases[j].event->desc) { 1652e5c6109fSIan Rogers name = aliases[j].event->name; 1653e5c6109fSIan Rogers buf_used = 0; 1654eb2d4514SIan Rogers } else { 1655eb2d4514SIan Rogers name = format_alias(buf, sizeof(buf), aliases[j].pmu, 1656eb2d4514SIan Rogers aliases[j].event); 1657e5c6109fSIan Rogers if (aliases[j].is_cpu) { 1658e5c6109fSIan Rogers alias = name; 1659e5c6109fSIan Rogers name = aliases[j].event->name; 1660eb2d4514SIan Rogers } 1661e5c6109fSIan Rogers buf_used = strlen(buf) + 1; 1662eb2d4514SIan Rogers } 1663e5c6109fSIan Rogers if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) { 1664e5c6109fSIan Rogers scale_unit = buf + buf_used; 1665e5c6109fSIan Rogers buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1666e5c6109fSIan Rogers "%G%s", aliases[j].event->scale, 1667e5c6109fSIan Rogers aliases[j].event->unit) + 1; 1668dc098b35SAndi Kleen } 1669e5c6109fSIan Rogers desc = aliases[j].event->desc; 1670e5c6109fSIan Rogers long_desc = aliases[j].event->long_desc; 1671eb2d4514SIan Rogers topic = aliases[j].event->topic; 1672e5c6109fSIan Rogers encoding_desc = buf + buf_used; 1673e5c6109fSIan Rogers buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1674e5c6109fSIan Rogers "%s/%s/", aliases[j].pmu->name, 1675e5c6109fSIan Rogers aliases[j].event->str) + 1; 1676e5c6109fSIan Rogers metric_name = aliases[j].event->metric_name; 1677e5c6109fSIan Rogers metric_expr = aliases[j].event->metric_expr; 1678e5c6109fSIan Rogers deprecated = aliases[j].event->deprecated; 1679dd5f1036SAndi Kleen } 1680e5c6109fSIan Rogers print_cb->print_event(print_state, 1681e5c6109fSIan Rogers aliases[j].pmu->name, 1682e5c6109fSIan Rogers topic, 1683e5c6109fSIan Rogers name, 1684e5c6109fSIan Rogers alias, 1685e5c6109fSIan Rogers scale_unit, 1686e5c6109fSIan Rogers deprecated, 1687e5c6109fSIan Rogers "Kernel PMU event", 1688e5c6109fSIan Rogers desc, 1689e5c6109fSIan Rogers long_desc, 1690e5c6109fSIan Rogers encoding_desc, 1691e5c6109fSIan Rogers metric_name, 1692e5c6109fSIan Rogers metric_expr); 1693dc098b35SAndi Kleen } 1694dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1695dc098b35SAndi Kleen printf("\n"); 1696eb2d4514SIan Rogers 16977e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 16987e4772dcSArnaldo Carvalho de Melo return; 1699dc098b35SAndi Kleen } 17004cabc3d1SAndi Kleen 17014cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 17024cabc3d1SAndi Kleen { 17034cabc3d1SAndi Kleen struct perf_pmu *pmu; 17044cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 17054cabc3d1SAndi Kleen 17064cabc3d1SAndi Kleen pmu = NULL; 17074cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 17084cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 17094cabc3d1SAndi Kleen continue; 17104cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 17114cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 17124cabc3d1SAndi Kleen return true; 17134cabc3d1SAndi Kleen } 17144cabc3d1SAndi Kleen return false; 17154cabc3d1SAndi Kleen } 17167d4bdab5SAdrian Hunter 1717d50a79cdSJames Clark FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 17187d4bdab5SAdrian Hunter { 17197d4bdab5SAdrian Hunter char path[PATH_MAX]; 17207d4bdab5SAdrian Hunter 1721f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name) || 1722f8ad6018SJames Clark !file_available(path)) 17237d4bdab5SAdrian Hunter return NULL; 17247d4bdab5SAdrian Hunter 17257d4bdab5SAdrian Hunter return fopen(path, "r"); 17267d4bdab5SAdrian Hunter } 17277d4bdab5SAdrian Hunter 17287d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 17297d4bdab5SAdrian Hunter ...) 17307d4bdab5SAdrian Hunter { 17317d4bdab5SAdrian Hunter va_list args; 17327d4bdab5SAdrian Hunter FILE *file; 17337d4bdab5SAdrian Hunter int ret = EOF; 17347d4bdab5SAdrian Hunter 17357d4bdab5SAdrian Hunter va_start(args, fmt); 17367d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 17377d4bdab5SAdrian Hunter if (file) { 17387d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 17397d4bdab5SAdrian Hunter fclose(file); 17407d4bdab5SAdrian Hunter } 17417d4bdab5SAdrian Hunter va_end(args); 17427d4bdab5SAdrian Hunter return ret; 17437d4bdab5SAdrian Hunter } 17449fbc61f8SKan Liang 1745*c2b6a896SGerman Gomez bool perf_pmu__file_exists(struct perf_pmu *pmu, const char *name) 1746*c2b6a896SGerman Gomez { 1747*c2b6a896SGerman Gomez char path[PATH_MAX]; 1748*c2b6a896SGerman Gomez 1749*c2b6a896SGerman Gomez if (!perf_pmu__pathname_scnprintf(path, sizeof(path), pmu->name, name)) 1750*c2b6a896SGerman Gomez return false; 1751*c2b6a896SGerman Gomez 1752*c2b6a896SGerman Gomez return file_available(path); 1753*c2b6a896SGerman Gomez } 1754*c2b6a896SGerman Gomez 17559fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 17569fbc61f8SKan Liang { 17579fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 17589fbc61f8SKan Liang 17599fbc61f8SKan Liang if (!caps) 17609fbc61f8SKan Liang return -ENOMEM; 17619fbc61f8SKan Liang 17629fbc61f8SKan Liang caps->name = strdup(name); 17639fbc61f8SKan Liang if (!caps->name) 17649fbc61f8SKan Liang goto free_caps; 17659fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 17669fbc61f8SKan Liang if (!caps->value) 17679fbc61f8SKan Liang goto free_name; 17689fbc61f8SKan Liang list_add_tail(&caps->list, list); 17699fbc61f8SKan Liang return 0; 17709fbc61f8SKan Liang 17719fbc61f8SKan Liang free_name: 17729fbc61f8SKan Liang zfree(caps->name); 17739fbc61f8SKan Liang free_caps: 17749fbc61f8SKan Liang free(caps); 17759fbc61f8SKan Liang 17769fbc61f8SKan Liang return -ENOMEM; 17779fbc61f8SKan Liang } 17789fbc61f8SKan Liang 17799fbc61f8SKan Liang /* 17809fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 17819fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 17829fbc61f8SKan Liang * Return the number of capabilities 17839fbc61f8SKan Liang */ 17849fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 17859fbc61f8SKan Liang { 17869fbc61f8SKan Liang struct stat st; 17879fbc61f8SKan Liang char caps_path[PATH_MAX]; 17889fbc61f8SKan Liang DIR *caps_dir; 17899fbc61f8SKan Liang struct dirent *evt_ent; 17903339ec44SRavi Bangoria 17913339ec44SRavi Bangoria if (pmu->caps_initialized) 17923339ec44SRavi Bangoria return pmu->nr_caps; 17933339ec44SRavi Bangoria 17943339ec44SRavi Bangoria pmu->nr_caps = 0; 17959fbc61f8SKan Liang 1796f8ad6018SJames Clark if (!perf_pmu__pathname_scnprintf(caps_path, sizeof(caps_path), pmu->name, "caps")) 17979fbc61f8SKan Liang return -1; 17989fbc61f8SKan Liang 17993339ec44SRavi Bangoria if (stat(caps_path, &st) < 0) { 18003339ec44SRavi Bangoria pmu->caps_initialized = true; 18019fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 18023339ec44SRavi Bangoria } 18039fbc61f8SKan Liang 18049fbc61f8SKan Liang caps_dir = opendir(caps_path); 18059fbc61f8SKan Liang if (!caps_dir) 18069fbc61f8SKan Liang return -EINVAL; 18079fbc61f8SKan Liang 18089fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 18099fbc61f8SKan Liang char path[PATH_MAX + NAME_MAX + 1]; 18109fbc61f8SKan Liang char *name = evt_ent->d_name; 18119fbc61f8SKan Liang char value[128]; 18129fbc61f8SKan Liang FILE *file; 18139fbc61f8SKan Liang 18149fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 18159fbc61f8SKan Liang continue; 18169fbc61f8SKan Liang 18179fbc61f8SKan Liang snprintf(path, sizeof(path), "%s/%s", caps_path, name); 18189fbc61f8SKan Liang 18199fbc61f8SKan Liang file = fopen(path, "r"); 18209fbc61f8SKan Liang if (!file) 18219fbc61f8SKan Liang continue; 18229fbc61f8SKan Liang 18239fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 18249fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 18259fbc61f8SKan Liang fclose(file); 18269fbc61f8SKan Liang continue; 18279fbc61f8SKan Liang } 18289fbc61f8SKan Liang 18293339ec44SRavi Bangoria pmu->nr_caps++; 18309fbc61f8SKan Liang fclose(file); 18319fbc61f8SKan Liang } 18329fbc61f8SKan Liang 18339fbc61f8SKan Liang closedir(caps_dir); 18349fbc61f8SKan Liang 18353339ec44SRavi Bangoria pmu->caps_initialized = true; 18363339ec44SRavi Bangoria return pmu->nr_caps; 18379fbc61f8SKan Liang } 1838e4064776SJin Yao 1839e4064776SJin Yao void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 18408e8bbfb3SIan Rogers const char *name) 1841e4064776SJin Yao { 1842e4064776SJin Yao struct perf_pmu_format *format; 1843e4064776SJin Yao __u64 masks = 0, bits; 1844e4064776SJin Yao char buf[100]; 1845e4064776SJin Yao unsigned int i; 1846e4064776SJin Yao 1847e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1848e4064776SJin Yao if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG) 1849e4064776SJin Yao continue; 1850e4064776SJin Yao 1851e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1852e4064776SJin Yao masks |= 1ULL << i; 1853e4064776SJin Yao } 1854e4064776SJin Yao 1855e4064776SJin Yao /* 1856e4064776SJin Yao * Kernel doesn't export any valid format bits. 1857e4064776SJin Yao */ 1858e4064776SJin Yao if (masks == 0) 1859e4064776SJin Yao return; 1860e4064776SJin Yao 1861e4064776SJin Yao bits = config & ~masks; 1862e4064776SJin Yao if (bits == 0) 1863e4064776SJin Yao return; 1864e4064776SJin Yao 1865e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1866e4064776SJin Yao 1867e4064776SJin Yao pr_warning("WARNING: event '%s' not valid (bits %s of config " 1868e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1869e4064776SJin Yao name ?: "N/A", buf, config); 1870e4064776SJin Yao } 1871c5a26ea4SJin Yao 1872c5a26ea4SJin Yao bool perf_pmu__has_hybrid(void) 1873c5a26ea4SJin Yao { 1874c5a26ea4SJin Yao if (!hybrid_scanned) { 1875c5a26ea4SJin Yao hybrid_scanned = true; 1876c5a26ea4SJin Yao perf_pmu__scan(NULL); 1877c5a26ea4SJin Yao } 1878c5a26ea4SJin Yao 1879c5a26ea4SJin Yao return !list_empty(&perf_pmu__hybrid_pmus); 1880c5a26ea4SJin Yao } 1881c47a5599SJin Yao 1882c47a5599SJin Yao int perf_pmu__match(char *pattern, char *name, char *tok) 1883c47a5599SJin Yao { 188413d60ba0SKan Liang if (!name) 188513d60ba0SKan Liang return -1; 188613d60ba0SKan Liang 1887c47a5599SJin Yao if (fnmatch(pattern, name, 0)) 1888c47a5599SJin Yao return -1; 1889c47a5599SJin Yao 1890c47a5599SJin Yao if (tok && !perf_pmu__valid_suffix(name, tok)) 1891c47a5599SJin Yao return -1; 1892c47a5599SJin Yao 1893c47a5599SJin Yao return 0; 1894c47a5599SJin Yao } 18951d3351e6SJin Yao 18961d3351e6SJin Yao int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus, 18971d3351e6SJin Yao struct perf_cpu_map **mcpus_ptr, 18981d3351e6SJin Yao struct perf_cpu_map **ucpus_ptr) 18991d3351e6SJin Yao { 19001d3351e6SJin Yao struct perf_cpu_map *pmu_cpus = pmu->cpus; 19011d3351e6SJin Yao struct perf_cpu_map *matched_cpus, *unmatched_cpus; 19026a12a63eSIan Rogers struct perf_cpu cpu; 19036a12a63eSIan Rogers int i, matched_nr = 0, unmatched_nr = 0; 19041d3351e6SJin Yao 19051d3351e6SJin Yao matched_cpus = perf_cpu_map__default_new(); 19061d3351e6SJin Yao if (!matched_cpus) 19071d3351e6SJin Yao return -1; 19081d3351e6SJin Yao 19091d3351e6SJin Yao unmatched_cpus = perf_cpu_map__default_new(); 19101d3351e6SJin Yao if (!unmatched_cpus) { 19111d3351e6SJin Yao perf_cpu_map__put(matched_cpus); 19121d3351e6SJin Yao return -1; 19131d3351e6SJin Yao } 19141d3351e6SJin Yao 19156a12a63eSIan Rogers perf_cpu_map__for_each_cpu(cpu, i, cpus) { 19166a12a63eSIan Rogers if (!perf_cpu_map__has(pmu_cpus, cpu)) 19176a12a63eSIan Rogers unmatched_cpus->map[unmatched_nr++] = cpu; 19181d3351e6SJin Yao else 19196a12a63eSIan Rogers matched_cpus->map[matched_nr++] = cpu; 19201d3351e6SJin Yao } 19211d3351e6SJin Yao 19221d3351e6SJin Yao unmatched_cpus->nr = unmatched_nr; 19231d3351e6SJin Yao matched_cpus->nr = matched_nr; 19241d3351e6SJin Yao *mcpus_ptr = matched_cpus; 19251d3351e6SJin Yao *ucpus_ptr = unmatched_cpus; 19261d3351e6SJin Yao return 0; 19271d3351e6SJin Yao } 1928acef233bSJing Zhang 1929acef233bSJing Zhang double __weak perf_pmu__cpu_slots_per_cycle(void) 1930acef233bSJing Zhang { 1931acef233bSJing Zhang return NAN; 1932acef233bSJing Zhang } 1933f8ad6018SJames Clark 1934f8ad6018SJames Clark int perf_pmu__event_source_devices_scnprintf(char *pathname, size_t size) 1935f8ad6018SJames Clark { 1936f8ad6018SJames Clark const char *sysfs = sysfs__mountpoint(); 1937f8ad6018SJames Clark 1938f8ad6018SJames Clark if (!sysfs) 1939f8ad6018SJames Clark return 0; 1940f8ad6018SJames Clark return scnprintf(pathname, size, "%s/bus/event_source/devices/", sysfs); 1941f8ad6018SJames Clark } 1942f8ad6018SJames Clark 1943f8ad6018SJames Clark /* 1944f8ad6018SJames Clark * Fill 'buf' with the path to a file or folder in 'pmu_name' in 1945f8ad6018SJames Clark * sysfs. For example if pmu_name = "cs_etm" and 'filename' = "format" 1946f8ad6018SJames Clark * then pathname will be filled with 1947f8ad6018SJames Clark * "/sys/bus/event_source/devices/cs_etm/format" 1948f8ad6018SJames Clark * 1949f8ad6018SJames Clark * Return 0 if the sysfs mountpoint couldn't be found or if no 1950f8ad6018SJames Clark * characters were written. 1951f8ad6018SJames Clark */ 1952f8ad6018SJames Clark int perf_pmu__pathname_scnprintf(char *buf, size_t size, 1953f8ad6018SJames Clark const char *pmu_name, const char *filename) 1954f8ad6018SJames Clark { 1955f8ad6018SJames Clark char base_path[PATH_MAX]; 1956f8ad6018SJames Clark 1957f8ad6018SJames Clark if (!perf_pmu__event_source_devices_scnprintf(base_path, sizeof(base_path))) 1958f8ad6018SJames Clark return 0; 1959f8ad6018SJames Clark return scnprintf(buf, size, "%s%s/%s", base_path, pmu_name, filename); 1960f8ad6018SJames Clark } 1961