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> 6fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h> 7cd82a32eSJiri Olsa #include <sys/types.h> 8a43783aeSArnaldo Carvalho de Melo #include <errno.h> 9c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h> 107a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 11cd82a32eSJiri Olsa #include <unistd.h> 12cd82a32eSJiri Olsa #include <stdio.h> 13dc0a6202SAdrian Hunter #include <stdbool.h> 147d4bdab5SAdrian Hunter #include <stdarg.h> 15cd82a32eSJiri Olsa #include <dirent.h> 16cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 17410136f5SStephane Eranian #include <locale.h> 18fbc2844eSWilliam Cohen #include <regex.h> 199c3516d1SJiri Olsa #include <perf/cpumap.h> 205e51b0bbSArnaldo Carvalho de Melo #include "debug.h" 21e12ee9f7SAdrian Hunter #include "evsel.h" 22cd82a32eSJiri Olsa #include "pmu.h" 23cd82a32eSJiri Olsa #include "parse-events.h" 24933f82ffSSukadev Bhattiprolu #include "header.h" 25a067558eSArnaldo Carvalho de Melo #include "string2.h" 26fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h" 27d9664582SAndi Kleen #include "fncache.h" 28cd82a32eSJiri Olsa 29e46fc8d9SArnaldo Carvalho de Melo struct perf_pmu perf_pmu__fake; 30e46fc8d9SArnaldo Carvalho de Melo 31ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 32ab1bf653SArnaldo Carvalho de Melo char *name; 33ab1bf653SArnaldo Carvalho de Melo int value; 34ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 35ab1bf653SArnaldo Carvalho de Melo struct list_head list; 36ab1bf653SArnaldo Carvalho de Melo }; 37ab1bf653SArnaldo Carvalho de Melo 38cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 39cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 40cd82a32eSJiri Olsa 41cd82a32eSJiri Olsa static LIST_HEAD(pmus); 42cd82a32eSJiri Olsa 43cd82a32eSJiri Olsa /* 44cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 45cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 46cd82a32eSJiri Olsa */ 47cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 48cd82a32eSJiri Olsa { 49cd82a32eSJiri Olsa struct dirent *evt_ent; 50cd82a32eSJiri Olsa DIR *format_dir; 51cd82a32eSJiri Olsa int ret = 0; 52cd82a32eSJiri Olsa 53cd82a32eSJiri Olsa format_dir = opendir(dir); 54cd82a32eSJiri Olsa if (!format_dir) 55cd82a32eSJiri Olsa return -EINVAL; 56cd82a32eSJiri Olsa 57cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 58cd82a32eSJiri Olsa char path[PATH_MAX]; 59cd82a32eSJiri Olsa char *name = evt_ent->d_name; 60cd82a32eSJiri Olsa FILE *file; 61cd82a32eSJiri Olsa 62cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 63cd82a32eSJiri Olsa continue; 64cd82a32eSJiri Olsa 65cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 66cd82a32eSJiri Olsa 67cd82a32eSJiri Olsa ret = -EINVAL; 68cd82a32eSJiri Olsa file = fopen(path, "r"); 69cd82a32eSJiri Olsa if (!file) 70cd82a32eSJiri Olsa break; 71cd82a32eSJiri Olsa 72cd82a32eSJiri Olsa perf_pmu_in = file; 73cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 74cd82a32eSJiri Olsa fclose(file); 75cd82a32eSJiri Olsa } 76cd82a32eSJiri Olsa 77cd82a32eSJiri Olsa closedir(format_dir); 78cd82a32eSJiri Olsa return ret; 79cd82a32eSJiri Olsa } 80cd82a32eSJiri Olsa 81cd82a32eSJiri Olsa /* 82cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 83cd82a32eSJiri Olsa * located at: 84cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 85cd82a32eSJiri Olsa */ 86b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 87cd82a32eSJiri Olsa { 88cd82a32eSJiri Olsa char path[PATH_MAX]; 89cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 90cd82a32eSJiri Olsa 91cd82a32eSJiri Olsa if (!sysfs) 92cd82a32eSJiri Olsa return -1; 93cd82a32eSJiri Olsa 94cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9550a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 96cd82a32eSJiri Olsa 97d9664582SAndi Kleen if (!file_available(path)) 98d9664582SAndi Kleen return 0; 99cd82a32eSJiri Olsa 100cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 101cd82a32eSJiri Olsa return -1; 102cd82a32eSJiri Olsa 103cd82a32eSJiri Olsa return 0; 104cd82a32eSJiri Olsa } 105cd82a32eSJiri Olsa 106a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 107d02fc6bcSAndi Kleen { 108d02fc6bcSAndi Kleen char *lc; 109d02fc6bcSAndi Kleen int ret = 0; 110d02fc6bcSAndi Kleen 111d02fc6bcSAndi Kleen /* 112d02fc6bcSAndi Kleen * save current locale 113d02fc6bcSAndi Kleen */ 114d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 115d02fc6bcSAndi Kleen 116d02fc6bcSAndi Kleen /* 117d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 118d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 119d02fc6bcSAndi Kleen * call below. 120d02fc6bcSAndi Kleen */ 121d02fc6bcSAndi Kleen lc = strdup(lc); 122d02fc6bcSAndi Kleen if (!lc) { 123d02fc6bcSAndi Kleen ret = -ENOMEM; 124d02fc6bcSAndi Kleen goto out; 125d02fc6bcSAndi Kleen } 126d02fc6bcSAndi Kleen 127d02fc6bcSAndi Kleen /* 128d02fc6bcSAndi Kleen * force to C locale to ensure kernel 129d02fc6bcSAndi Kleen * scale string is converted correctly. 130d02fc6bcSAndi Kleen * kernel uses default C locale. 131d02fc6bcSAndi Kleen */ 132d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 133d02fc6bcSAndi Kleen 134d02fc6bcSAndi Kleen *sval = strtod(scale, end); 135d02fc6bcSAndi Kleen 136d02fc6bcSAndi Kleen out: 137d02fc6bcSAndi Kleen /* restore locale */ 138d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 139d02fc6bcSAndi Kleen free(lc); 140d02fc6bcSAndi Kleen return ret; 141d02fc6bcSAndi Kleen } 142d02fc6bcSAndi Kleen 143410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 144410136f5SStephane Eranian { 145410136f5SStephane Eranian struct stat st; 146410136f5SStephane Eranian ssize_t sret; 147410136f5SStephane Eranian char scale[128]; 148410136f5SStephane Eranian int fd, ret = -1; 149410136f5SStephane Eranian char path[PATH_MAX]; 150410136f5SStephane Eranian 15111a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 152410136f5SStephane Eranian 153410136f5SStephane Eranian fd = open(path, O_RDONLY); 154410136f5SStephane Eranian if (fd == -1) 155410136f5SStephane Eranian return -1; 156410136f5SStephane Eranian 157410136f5SStephane Eranian if (fstat(fd, &st) < 0) 158410136f5SStephane Eranian goto error; 159410136f5SStephane Eranian 160410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 161410136f5SStephane Eranian if (sret < 0) 162410136f5SStephane Eranian goto error; 163410136f5SStephane Eranian 1649ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1659ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1669ecae065SMadhavan Srinivasan else 167410136f5SStephane Eranian scale[sret] = '\0'; 1689ecae065SMadhavan Srinivasan 169a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 170410136f5SStephane Eranian error: 171410136f5SStephane Eranian close(fd); 172410136f5SStephane Eranian return ret; 173410136f5SStephane Eranian } 174410136f5SStephane Eranian 175410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 176410136f5SStephane Eranian { 177410136f5SStephane Eranian char path[PATH_MAX]; 178410136f5SStephane Eranian ssize_t sret; 179410136f5SStephane Eranian int fd; 180410136f5SStephane Eranian 18111a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 182410136f5SStephane Eranian 183410136f5SStephane Eranian fd = open(path, O_RDONLY); 184410136f5SStephane Eranian if (fd == -1) 185410136f5SStephane Eranian return -1; 186410136f5SStephane Eranian 187410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 188410136f5SStephane Eranian if (sret < 0) 189410136f5SStephane Eranian goto error; 190410136f5SStephane Eranian 191410136f5SStephane Eranian close(fd); 192410136f5SStephane Eranian 1939ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1949ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1959ecae065SMadhavan Srinivasan else 196410136f5SStephane Eranian alias->unit[sret] = '\0'; 197410136f5SStephane Eranian 198410136f5SStephane Eranian return 0; 199410136f5SStephane Eranian error: 200410136f5SStephane Eranian close(fd); 201410136f5SStephane Eranian alias->unit[0] = '\0'; 202410136f5SStephane Eranian return -1; 203410136f5SStephane Eranian } 204410136f5SStephane Eranian 205044330c1SMatt Fleming static int 206044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 207044330c1SMatt Fleming { 208044330c1SMatt Fleming char path[PATH_MAX]; 209044330c1SMatt Fleming int fd; 210044330c1SMatt Fleming 21111a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 212044330c1SMatt Fleming 213044330c1SMatt Fleming fd = open(path, O_RDONLY); 214044330c1SMatt Fleming if (fd == -1) 215044330c1SMatt Fleming return -1; 216044330c1SMatt Fleming 217044330c1SMatt Fleming close(fd); 218044330c1SMatt Fleming 219044330c1SMatt Fleming alias->per_pkg = true; 220044330c1SMatt Fleming return 0; 221044330c1SMatt Fleming } 222044330c1SMatt Fleming 2231d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2241d9e446bSJiri Olsa char *dir, char *name) 2251d9e446bSJiri Olsa { 2261d9e446bSJiri Olsa char path[PATH_MAX]; 2271d9e446bSJiri Olsa int fd; 2281d9e446bSJiri Olsa 22911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2301d9e446bSJiri Olsa 2311d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2321d9e446bSJiri Olsa if (fd == -1) 2331d9e446bSJiri Olsa return -1; 2341d9e446bSJiri Olsa 2351d9e446bSJiri Olsa alias->snapshot = true; 2361d9e446bSJiri Olsa close(fd); 2371d9e446bSJiri Olsa return 0; 2381d9e446bSJiri Olsa } 2391d9e446bSJiri Olsa 2406dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2416dde6429SThomas Richter char **new_str) 2426dde6429SThomas Richter { 2436dde6429SThomas Richter if (!*old_str) 2446dde6429SThomas Richter goto set_new; 2456dde6429SThomas Richter 2466dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2476dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2486dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2496dde6429SThomas Richter name, field); 2506dde6429SThomas Richter zfree(old_str); 2516dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2526dde6429SThomas Richter return; 2536dde6429SThomas Richter set_new: 2546dde6429SThomas Richter *old_str = *new_str; 2556dde6429SThomas Richter *new_str = NULL; 2566dde6429SThomas Richter } 2576dde6429SThomas Richter 2586dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2596dde6429SThomas Richter struct perf_pmu_alias *newalias) 2606dde6429SThomas Richter { 2616dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2626dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2636dde6429SThomas Richter &newalias->long_desc); 2646dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2656dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, 2666dde6429SThomas Richter &newalias->metric_expr); 2676dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, 2686dde6429SThomas Richter &newalias->metric_name); 2696dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2706dde6429SThomas Richter old->scale = newalias->scale; 2716dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2726dde6429SThomas Richter old->snapshot = newalias->snapshot; 2736dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2746dde6429SThomas Richter } 2756dde6429SThomas Richter 2766dde6429SThomas Richter /* Delete an alias entry. */ 27722fe5a25SNamhyung Kim void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2786dde6429SThomas Richter { 2796dde6429SThomas Richter zfree(&newalias->name); 2806dde6429SThomas Richter zfree(&newalias->desc); 2816dde6429SThomas Richter zfree(&newalias->long_desc); 2826dde6429SThomas Richter zfree(&newalias->topic); 2836dde6429SThomas Richter zfree(&newalias->str); 2846dde6429SThomas Richter zfree(&newalias->metric_expr); 2856dde6429SThomas Richter zfree(&newalias->metric_name); 2866dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 2876dde6429SThomas Richter free(newalias); 2886dde6429SThomas Richter } 2896dde6429SThomas Richter 2906dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 2916dde6429SThomas Richter * present merge both of them to combine all information. 2926dde6429SThomas Richter */ 2936dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 2946dde6429SThomas Richter struct list_head *alist) 2956dde6429SThomas Richter { 2966dde6429SThomas Richter struct perf_pmu_alias *a; 2976dde6429SThomas Richter 2986dde6429SThomas Richter list_for_each_entry(a, alist, list) { 2996dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 3006dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 3016dde6429SThomas Richter perf_pmu_free_alias(newalias); 3026dde6429SThomas Richter return true; 3036dde6429SThomas Richter } 3046dde6429SThomas Richter } 3056dde6429SThomas Richter return false; 3066dde6429SThomas Richter } 3076dde6429SThomas Richter 30870c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 309fedb2b51SAndi Kleen char *desc, char *val, 310fedb2b51SAndi Kleen char *long_desc, char *topic, 31100636c3bSAndi Kleen char *unit, char *perpkg, 31296284814SAndi Kleen char *metric_expr, 313a7f6c8c8SJin Yao char *metric_name, 314a7f6c8c8SJin Yao char *deprecated) 315a6146d50SZheng Yan { 3160c24d6fbSThomas Richter struct parse_events_term *term; 3175c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 318a6146d50SZheng Yan int ret; 319fedb2b51SAndi Kleen int num; 3200c24d6fbSThomas Richter char newval[256]; 321a6146d50SZheng Yan 322a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 323a6146d50SZheng Yan if (!alias) 324a6146d50SZheng Yan return -ENOMEM; 325a6146d50SZheng Yan 326a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 327410136f5SStephane Eranian alias->scale = 1.0; 328410136f5SStephane Eranian alias->unit[0] = '\0'; 329044330c1SMatt Fleming alias->per_pkg = false; 33084530920SStephane Eranian alias->snapshot = false; 331a7f6c8c8SJin Yao alias->deprecated = false; 332410136f5SStephane Eranian 33370c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 334a6146d50SZheng Yan if (ret) { 33570c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 336a6146d50SZheng Yan free(alias); 337a6146d50SZheng Yan return ret; 338a6146d50SZheng Yan } 339a6146d50SZheng Yan 3400c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3410c24d6fbSThomas Richter * platforms have terms specified as 3420c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3430c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3440c24d6fbSThomas Richter * 3450c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3460c24d6fbSThomas Richter */ 3470c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3480c24d6fbSThomas Richter ret = 0; 3490c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3500c24d6fbSThomas Richter if (ret) 3510c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3520c24d6fbSThomas Richter ","); 3530c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3540c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3550c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3560c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3570c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3580c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3590c24d6fbSThomas Richter } 3600c24d6fbSThomas Richter 361a6146d50SZheng Yan alias->name = strdup(name); 36270c646e0SSukadev Bhattiprolu if (dir) { 363410136f5SStephane Eranian /* 364410136f5SStephane Eranian * load unit name and scale if available 365410136f5SStephane Eranian */ 366410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 367410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 368044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 3691d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 37070c646e0SSukadev Bhattiprolu } 371410136f5SStephane Eranian 37200636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 37396284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 37408e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 375c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 376c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 377dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 378fedb2b51SAndi Kleen if (unit) { 379a55ab7c4SJin Yao if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) 380fedb2b51SAndi Kleen return -1; 381fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 382fedb2b51SAndi Kleen } 383fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 3840c24d6fbSThomas Richter alias->str = strdup(newval); 385f2361024SAndi Kleen 386a7f6c8c8SJin Yao if (deprecated) 387a7f6c8c8SJin Yao alias->deprecated = true; 388a7f6c8c8SJin Yao 3896dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 390a6146d50SZheng Yan list_add_tail(&alias->list, list); 391410136f5SStephane Eranian 392a6146d50SZheng Yan return 0; 393a6146d50SZheng Yan } 394a6146d50SZheng Yan 39570c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 39670c646e0SSukadev Bhattiprolu { 39770c646e0SSukadev Bhattiprolu char buf[256]; 39870c646e0SSukadev Bhattiprolu int ret; 39970c646e0SSukadev Bhattiprolu 40070c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 40170c646e0SSukadev Bhattiprolu if (ret == 0) 40270c646e0SSukadev Bhattiprolu return -EINVAL; 40370c646e0SSukadev Bhattiprolu 40470c646e0SSukadev Bhattiprolu buf[ret] = 0; 40570c646e0SSukadev Bhattiprolu 406ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 40713c230abSArnaldo Carvalho de Melo strim(buf); 408ea23ac73SThomas Richter 409fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 410a7f6c8c8SJin Yao NULL, NULL, NULL, NULL); 41170c646e0SSukadev Bhattiprolu } 41270c646e0SSukadev Bhattiprolu 41346441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 41446441bdcSMatt Fleming { 41546441bdcSMatt Fleming size_t len; 41646441bdcSMatt Fleming 41746441bdcSMatt Fleming len = strlen(name); 41846441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 41946441bdcSMatt Fleming return true; 42046441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 42146441bdcSMatt Fleming return true; 422044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 423044330c1SMatt Fleming return true; 4241d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4251d9e446bSJiri Olsa return true; 42646441bdcSMatt Fleming 42746441bdcSMatt Fleming return false; 42846441bdcSMatt Fleming } 42946441bdcSMatt Fleming 430a6146d50SZheng Yan /* 431a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 432a6146d50SZheng Yan * specified in 'dir' parameter. 433a6146d50SZheng Yan */ 434a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 435a6146d50SZheng Yan { 436a6146d50SZheng Yan struct dirent *evt_ent; 437a6146d50SZheng Yan DIR *event_dir; 438a6146d50SZheng Yan 439a6146d50SZheng Yan event_dir = opendir(dir); 440a6146d50SZheng Yan if (!event_dir) 441a6146d50SZheng Yan return -EINVAL; 442a6146d50SZheng Yan 443940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 444a6146d50SZheng Yan char path[PATH_MAX]; 445a6146d50SZheng Yan char *name = evt_ent->d_name; 446a6146d50SZheng Yan FILE *file; 447a6146d50SZheng Yan 448a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 449a6146d50SZheng Yan continue; 450a6146d50SZheng Yan 451410136f5SStephane Eranian /* 45246441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 453410136f5SStephane Eranian */ 45446441bdcSMatt Fleming if (pmu_alias_info_file(name)) 455410136f5SStephane Eranian continue; 456410136f5SStephane Eranian 45777f18153SJiri Olsa scnprintf(path, PATH_MAX, "%s/%s", dir, name); 458a6146d50SZheng Yan 459a6146d50SZheng Yan file = fopen(path, "r"); 460940db6dcSAndi Kleen if (!file) { 461940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 462940db6dcSAndi Kleen continue; 463940db6dcSAndi Kleen } 464410136f5SStephane Eranian 465940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 466940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 467a6146d50SZheng Yan fclose(file); 468a6146d50SZheng Yan } 469a6146d50SZheng Yan 470a6146d50SZheng Yan closedir(event_dir); 471940db6dcSAndi Kleen return 0; 472a6146d50SZheng Yan } 473a6146d50SZheng Yan 474a6146d50SZheng Yan /* 475a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 476a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 477a6146d50SZheng Yan */ 478b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 479a6146d50SZheng Yan { 480a6146d50SZheng Yan char path[PATH_MAX]; 481cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 482a6146d50SZheng Yan 483a6146d50SZheng Yan if (!sysfs) 484a6146d50SZheng Yan return -1; 485a6146d50SZheng Yan 486a6146d50SZheng Yan snprintf(path, PATH_MAX, 487a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 488a6146d50SZheng Yan 489d9664582SAndi Kleen if (!file_available(path)) 490d9664582SAndi Kleen return 0; 491a6146d50SZheng Yan 492a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 493a6146d50SZheng Yan return -1; 494a6146d50SZheng Yan 495a6146d50SZheng Yan return 0; 496a6146d50SZheng Yan } 497a6146d50SZheng Yan 4985c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 499a6146d50SZheng Yan struct list_head *terms) 500a6146d50SZheng Yan { 5017c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 502a6146d50SZheng Yan LIST_HEAD(list); 503a6146d50SZheng Yan int ret; 504a6146d50SZheng Yan 505a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5067c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 507a6146d50SZheng Yan if (ret) { 508682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 509a6146d50SZheng Yan return ret; 510a6146d50SZheng Yan } 511c2f1ceadSAndi Kleen /* 512c2f1ceadSAndi Kleen * Weak terms don't override command line options, 513c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 514c2f1ceadSAndi Kleen */ 515c2f1ceadSAndi Kleen cloned->weak = true; 5167c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 517a6146d50SZheng Yan } 518a6146d50SZheng Yan list_splice(&list, terms); 519a6146d50SZheng Yan return 0; 520a6146d50SZheng Yan } 521a6146d50SZheng Yan 522cd82a32eSJiri Olsa /* 523cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 524cd82a32eSJiri Olsa * located at: 525cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 526cd82a32eSJiri Olsa */ 527b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 528cd82a32eSJiri Olsa { 529cd82a32eSJiri Olsa char path[PATH_MAX]; 530cd82a32eSJiri Olsa FILE *file; 531cd82a32eSJiri Olsa int ret = 0; 532cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 533cd82a32eSJiri Olsa 534cd82a32eSJiri Olsa if (!sysfs) 535cd82a32eSJiri Olsa return -1; 536cd82a32eSJiri Olsa 537cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 53850a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 539cd82a32eSJiri Olsa 540d9664582SAndi Kleen if (access(path, R_OK) < 0) 541cd82a32eSJiri Olsa return -1; 542cd82a32eSJiri Olsa 543cd82a32eSJiri Olsa file = fopen(path, "r"); 544cd82a32eSJiri Olsa if (!file) 545cd82a32eSJiri Olsa return -EINVAL; 546cd82a32eSJiri Olsa 547cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 548cd82a32eSJiri Olsa ret = -1; 549cd82a32eSJiri Olsa 550cd82a32eSJiri Olsa fclose(file); 551cd82a32eSJiri Olsa return ret; 552cd82a32eSJiri Olsa } 553cd82a32eSJiri Olsa 55450a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 55550a9667cSRobert Richter static void pmu_read_sysfs(void) 55650a9667cSRobert Richter { 55750a9667cSRobert Richter char path[PATH_MAX]; 55850a9667cSRobert Richter DIR *dir; 55950a9667cSRobert Richter struct dirent *dent; 560cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 56150a9667cSRobert Richter 56250a9667cSRobert Richter if (!sysfs) 56350a9667cSRobert Richter return; 56450a9667cSRobert Richter 56550a9667cSRobert Richter snprintf(path, PATH_MAX, 56650a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 56750a9667cSRobert Richter 56850a9667cSRobert Richter dir = opendir(path); 56950a9667cSRobert Richter if (!dir) 57050a9667cSRobert Richter return; 57150a9667cSRobert Richter 57250a9667cSRobert Richter while ((dent = readdir(dir))) { 57350a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 57450a9667cSRobert Richter continue; 57550a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 57650a9667cSRobert Richter perf_pmu__find(dent->d_name); 57750a9667cSRobert Richter } 57850a9667cSRobert Richter 57950a9667cSRobert Richter closedir(dir); 58050a9667cSRobert Richter } 58150a9667cSRobert Richter 582f854839bSJiri Olsa static struct perf_cpu_map *__pmu_cpumask(const char *path) 58366ec1191SMark Rutland { 58466ec1191SMark Rutland FILE *file; 585f854839bSJiri Olsa struct perf_cpu_map *cpus; 58666ec1191SMark Rutland 58766ec1191SMark Rutland file = fopen(path, "r"); 58866ec1191SMark Rutland if (!file) 58966ec1191SMark Rutland return NULL; 59066ec1191SMark Rutland 5919c3516d1SJiri Olsa cpus = perf_cpu_map__read(file); 59266ec1191SMark Rutland fclose(file); 59366ec1191SMark Rutland return cpus; 59466ec1191SMark Rutland } 59566ec1191SMark Rutland 59666ec1191SMark Rutland /* 59766ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 59866ec1191SMark Rutland * may have a "cpus" file. 59966ec1191SMark Rutland */ 60051d54847SJohn Garry #define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier" 60166ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 60266ec1191SMark Rutland #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 60366ec1191SMark Rutland 604f854839bSJiri Olsa static struct perf_cpu_map *pmu_cpumask(const char *name) 6057ae92e74SYan, Zheng { 6067ae92e74SYan, Zheng char path[PATH_MAX]; 607f854839bSJiri Olsa struct perf_cpu_map *cpus; 608cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 6097e3fcffeSMark Rutland const char *templates[] = { 61066ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 61166ec1191SMark Rutland CPUS_TEMPLATE_CPU, 6127e3fcffeSMark Rutland NULL 6137e3fcffeSMark Rutland }; 6147e3fcffeSMark Rutland const char **template; 6157ae92e74SYan, Zheng 6167ae92e74SYan, Zheng if (!sysfs) 6177ae92e74SYan, Zheng return NULL; 6187ae92e74SYan, Zheng 6197e3fcffeSMark Rutland for (template = templates; *template; template++) { 6207e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 62166ec1191SMark Rutland cpus = __pmu_cpumask(path); 62266ec1191SMark Rutland if (cpus) 62366ec1191SMark Rutland return cpus; 6247e3fcffeSMark Rutland } 6257ae92e74SYan, Zheng 6267ae92e74SYan, Zheng return NULL; 62766ec1191SMark Rutland } 6287ae92e74SYan, Zheng 62966ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 63066ec1191SMark Rutland { 63166ec1191SMark Rutland char path[PATH_MAX]; 632d9664582SAndi Kleen const char *sysfs; 6337ae92e74SYan, Zheng 634d9664582SAndi Kleen sysfs = sysfs__mountpoint(); 63566ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 636d9664582SAndi Kleen return file_available(path); 6377ae92e74SYan, Zheng } 6387ae92e74SYan, Zheng 63951d54847SJohn Garry static char *pmu_id(const char *name) 64051d54847SJohn Garry { 64151d54847SJohn Garry char path[PATH_MAX], *str; 64251d54847SJohn Garry size_t len; 64351d54847SJohn Garry 64451d54847SJohn Garry snprintf(path, PATH_MAX, SYS_TEMPLATE_ID, name); 64551d54847SJohn Garry 64651d54847SJohn Garry if (sysfs__read_str(path, &str, &len) < 0) 64751d54847SJohn Garry return NULL; 64851d54847SJohn Garry 64951d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 65051d54847SJohn Garry 65151d54847SJohn Garry return str; 65251d54847SJohn Garry } 65351d54847SJohn Garry 654933f82ffSSukadev Bhattiprolu /* 65514b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 656292c34c1SKan Liang * platforms. 657292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 65814b22ae0SGanapatrao Kulkarni */ 659292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 66014b22ae0SGanapatrao Kulkarni { 66114b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 66214b22ae0SGanapatrao Kulkarni const char *sysfs = sysfs__mountpoint(); 66314b22ae0SGanapatrao Kulkarni 66414b22ae0SGanapatrao Kulkarni if (!sysfs) 66514b22ae0SGanapatrao Kulkarni return 0; 66614b22ae0SGanapatrao Kulkarni 66714b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (specific to arm) */ 66814b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", 66914b22ae0SGanapatrao Kulkarni sysfs, name); 670d9664582SAndi Kleen return file_available(path); 67114b22ae0SGanapatrao Kulkarni } 67214b22ae0SGanapatrao Kulkarni 67354e32dc0SGanapatrao Kulkarni static char *perf_pmu__getcpuid(struct perf_pmu *pmu) 674d77ade9fSAndi Kleen { 675d77ade9fSAndi Kleen char *cpuid; 676d77ade9fSAndi Kleen static bool printed; 677d77ade9fSAndi Kleen 678d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 679d77ade9fSAndi Kleen if (cpuid) 680d77ade9fSAndi Kleen cpuid = strdup(cpuid); 681d77ade9fSAndi Kleen if (!cpuid) 68254e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 683d77ade9fSAndi Kleen if (!cpuid) 684d77ade9fSAndi Kleen return NULL; 685d77ade9fSAndi Kleen 686d77ade9fSAndi Kleen if (!printed) { 687d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 688d77ade9fSAndi Kleen printed = true; 689d77ade9fSAndi Kleen } 690d77ade9fSAndi Kleen return cpuid; 691d77ade9fSAndi Kleen } 692d77ade9fSAndi Kleen 69354e32dc0SGanapatrao Kulkarni struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu) 694d77ade9fSAndi Kleen { 695d77ade9fSAndi Kleen struct pmu_events_map *map; 69654e32dc0SGanapatrao Kulkarni char *cpuid = perf_pmu__getcpuid(pmu); 697d77ade9fSAndi Kleen int i; 698d77ade9fSAndi Kleen 699de3d0f12SGanapatrao Kulkarni /* on some platforms which uses cpus map, cpuid can be NULL for 700de3d0f12SGanapatrao Kulkarni * PMUs other than CORE PMUs. 701de3d0f12SGanapatrao Kulkarni */ 702de3d0f12SGanapatrao Kulkarni if (!cpuid) 703de3d0f12SGanapatrao Kulkarni return NULL; 704de3d0f12SGanapatrao Kulkarni 705d77ade9fSAndi Kleen i = 0; 706d77ade9fSAndi Kleen for (;;) { 707d77ade9fSAndi Kleen map = &pmu_events_map[i++]; 708d77ade9fSAndi Kleen if (!map->table) { 709d77ade9fSAndi Kleen map = NULL; 710d77ade9fSAndi Kleen break; 711d77ade9fSAndi Kleen } 712d77ade9fSAndi Kleen 7134cb7d3ecSThomas Richter if (!strcmp_cpuid_str(map->cpuid, cpuid)) 714d77ade9fSAndi Kleen break; 715d77ade9fSAndi Kleen } 716d77ade9fSAndi Kleen free(cpuid); 717d77ade9fSAndi Kleen return map; 718d77ade9fSAndi Kleen } 719d77ade9fSAndi Kleen 720*e126bef5SJohn Garry struct pmu_events_map *__weak pmu_events_map__find(void) 721*e126bef5SJohn Garry { 722*e126bef5SJohn Garry return perf_pmu__find_map(NULL); 723*e126bef5SJohn Garry } 724*e126bef5SJohn Garry 7255b9a5000SJohn Garry bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 726730670b1SJohn Garry { 727730670b1SJohn Garry char *tmp = NULL, *tok, *str; 728730670b1SJohn Garry bool res; 729730670b1SJohn Garry 730730670b1SJohn Garry str = strdup(pmu_name); 731730670b1SJohn Garry if (!str) 732730670b1SJohn Garry return false; 733730670b1SJohn Garry 734730670b1SJohn Garry /* 735730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 736730670b1SJohn Garry */ 737730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 738730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 739730670b1SJohn Garry res = false; 740730670b1SJohn Garry goto out; 741730670b1SJohn Garry } 742730670b1SJohn Garry 743730670b1SJohn Garry /* 744730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 745730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 746730670b1SJohn Garry * 747730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 748730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 749730670b1SJohn Garry * "pmunameY". 750730670b1SJohn Garry */ 751730670b1SJohn Garry for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) { 752730670b1SJohn Garry name = strstr(name, tok); 753730670b1SJohn Garry if (!name) { 754730670b1SJohn Garry res = false; 755730670b1SJohn Garry goto out; 756730670b1SJohn Garry } 757730670b1SJohn Garry } 758730670b1SJohn Garry 759730670b1SJohn Garry res = true; 760730670b1SJohn Garry out: 761730670b1SJohn Garry free(str); 762730670b1SJohn Garry return res; 763730670b1SJohn Garry } 764730670b1SJohn Garry 765933f82ffSSukadev Bhattiprolu /* 766933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 767933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 768933f82ffSSukadev Bhattiprolu * as aliases. 769933f82ffSSukadev Bhattiprolu */ 770e45ad701SJohn Garry void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu, 771e45ad701SJohn Garry struct pmu_events_map *map) 772933f82ffSSukadev Bhattiprolu { 773933f82ffSSukadev Bhattiprolu int i; 77454e32dc0SGanapatrao Kulkarni const char *name = pmu->name; 775933f82ffSSukadev Bhattiprolu /* 776933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 777933f82ffSSukadev Bhattiprolu */ 778933f82ffSSukadev Bhattiprolu i = 0; 779933f82ffSSukadev Bhattiprolu while (1) { 780599ee18fSJohn Garry const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu"; 781599ee18fSJohn Garry struct pmu_event *pe = &map->table[i++]; 782599ee18fSJohn Garry const char *pname = pe->pmu ? pe->pmu : cpu_name; 783fedb2b51SAndi Kleen 784b18f3e36SAndi Kleen if (!pe->name) { 785b18f3e36SAndi Kleen if (pe->metric_group || pe->metric_name) 786b18f3e36SAndi Kleen continue; 787933f82ffSSukadev Bhattiprolu break; 788b18f3e36SAndi Kleen } 789933f82ffSSukadev Bhattiprolu 790e94d6b7fSKan Liang if (pmu_is_uncore(name) && 791730670b1SJohn Garry pmu_uncore_alias_match(pname, name)) 792e94d6b7fSKan Liang goto new_alias; 793e94d6b7fSKan Liang 794ea1fa48cSThomas Richter if (strcmp(pname, name)) 79514b22ae0SGanapatrao Kulkarni continue; 796fedb2b51SAndi Kleen 797e94d6b7fSKan Liang new_alias: 798933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 799933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 800c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 801fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 80200636c3bSAndi Kleen (char *)pe->unit, (char *)pe->perpkg, 80396284814SAndi Kleen (char *)pe->metric_expr, 804a7f6c8c8SJin Yao (char *)pe->metric_name, 805a7f6c8c8SJin Yao (char *)pe->deprecated); 806933f82ffSSukadev Bhattiprolu } 807933f82ffSSukadev Bhattiprolu } 808933f82ffSSukadev Bhattiprolu 809e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 810e45ad701SJohn Garry { 811e45ad701SJohn Garry struct pmu_events_map *map; 812e45ad701SJohn Garry 813e45ad701SJohn Garry map = perf_pmu__find_map(pmu); 814e45ad701SJohn Garry if (!map) 815e45ad701SJohn Garry return; 816e45ad701SJohn Garry 817e45ad701SJohn Garry pmu_add_cpu_aliases_map(head, pmu, map); 818e45ad701SJohn Garry } 819e45ad701SJohn Garry 8204513c719SJohn Garry void pmu_for_each_sys_event(pmu_sys_event_iter_fn fn, void *data) 8214513c719SJohn Garry { 8224513c719SJohn Garry int i = 0; 8234513c719SJohn Garry 8244513c719SJohn Garry while (1) { 8254513c719SJohn Garry struct pmu_sys_events *event_table; 8264513c719SJohn Garry int j = 0; 8274513c719SJohn Garry 8284513c719SJohn Garry event_table = &pmu_sys_event_tables[i++]; 8294513c719SJohn Garry 8304513c719SJohn Garry if (!event_table->table) 8314513c719SJohn Garry break; 8324513c719SJohn Garry 8334513c719SJohn Garry while (1) { 8344513c719SJohn Garry struct pmu_event *pe = &event_table->table[j++]; 8354513c719SJohn Garry int ret; 8364513c719SJohn Garry 8374513c719SJohn Garry if (!pe->name && !pe->metric_group && !pe->metric_name) 8384513c719SJohn Garry break; 8394513c719SJohn Garry 8404513c719SJohn Garry ret = fn(pe, data); 8414513c719SJohn Garry if (ret) 8424513c719SJohn Garry break; 8434513c719SJohn Garry } 8444513c719SJohn Garry } 8454513c719SJohn Garry } 8464513c719SJohn Garry 8474513c719SJohn Garry struct pmu_sys_event_iter_data { 8484513c719SJohn Garry struct list_head *head; 8494513c719SJohn Garry struct perf_pmu *pmu; 8504513c719SJohn Garry }; 8514513c719SJohn Garry 8524513c719SJohn Garry static int pmu_add_sys_aliases_iter_fn(struct pmu_event *pe, void *data) 8534513c719SJohn Garry { 8544513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8554513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8564513c719SJohn Garry 8574513c719SJohn Garry if (!pe->name) { 8584513c719SJohn Garry if (pe->metric_group || pe->metric_name) 8594513c719SJohn Garry return 0; 8604513c719SJohn Garry return -EINVAL; 8614513c719SJohn Garry } 8624513c719SJohn Garry 8634513c719SJohn Garry if (!pe->compat || !pe->pmu) 8644513c719SJohn Garry return 0; 8654513c719SJohn Garry 8664513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8674513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 8684513c719SJohn Garry __perf_pmu__new_alias(idata->head, NULL, 8694513c719SJohn Garry (char *)pe->name, 8704513c719SJohn Garry (char *)pe->desc, 8714513c719SJohn Garry (char *)pe->event, 8724513c719SJohn Garry (char *)pe->long_desc, 8734513c719SJohn Garry (char *)pe->topic, 8744513c719SJohn Garry (char *)pe->unit, 8754513c719SJohn Garry (char *)pe->perpkg, 8764513c719SJohn Garry (char *)pe->metric_expr, 8774513c719SJohn Garry (char *)pe->metric_name, 8784513c719SJohn Garry (char *)pe->deprecated); 8794513c719SJohn Garry } 8804513c719SJohn Garry 8814513c719SJohn Garry return 0; 8824513c719SJohn Garry } 8834513c719SJohn Garry 8844513c719SJohn Garry static void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 8854513c719SJohn Garry { 8864513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 8874513c719SJohn Garry .head = head, 8884513c719SJohn Garry .pmu = pmu, 8894513c719SJohn Garry }; 8904513c719SJohn Garry 8914513c719SJohn Garry if (!pmu->id) 8924513c719SJohn Garry return; 8934513c719SJohn Garry 8944513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 8954513c719SJohn Garry } 8964513c719SJohn Garry 897c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 898dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 899dc0a6202SAdrian Hunter { 900dc0a6202SAdrian Hunter return NULL; 901dc0a6202SAdrian Hunter } 902dc0a6202SAdrian Hunter 90390a86bdeSJiri Olsa static int pmu_max_precise(const char *name) 90490a86bdeSJiri Olsa { 90590a86bdeSJiri Olsa char path[PATH_MAX]; 90690a86bdeSJiri Olsa int max_precise = -1; 90790a86bdeSJiri Olsa 90890a86bdeSJiri Olsa scnprintf(path, PATH_MAX, 90990a86bdeSJiri Olsa "bus/event_source/devices/%s/caps/max_precise", 91090a86bdeSJiri Olsa name); 91190a86bdeSJiri Olsa 91290a86bdeSJiri Olsa sysfs__read_int(path, &max_precise); 91390a86bdeSJiri Olsa return max_precise; 91490a86bdeSJiri Olsa } 91590a86bdeSJiri Olsa 916b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 917cd82a32eSJiri Olsa { 918cd82a32eSJiri Olsa struct perf_pmu *pmu; 919cd82a32eSJiri Olsa LIST_HEAD(format); 920a6146d50SZheng Yan LIST_HEAD(aliases); 921cd82a32eSJiri Olsa __u32 type; 922cd82a32eSJiri Olsa 923cd82a32eSJiri Olsa /* 924cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 925cd82a32eSJiri Olsa * type value and format definitions. Load both right 926cd82a32eSJiri Olsa * now. 927cd82a32eSJiri Olsa */ 928cd82a32eSJiri Olsa if (pmu_format(name, &format)) 929cd82a32eSJiri Olsa return NULL; 930cd82a32eSJiri Olsa 93115b22ed3SAndi Kleen /* 93215b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 93315b22ed3SAndi Kleen */ 93415b22ed3SAndi Kleen if (pmu_type(name, &type)) 93515b22ed3SAndi Kleen return NULL; 93615b22ed3SAndi Kleen 9373fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 9383fded963SJiri Olsa return NULL; 9393fded963SJiri Olsa 940cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 941cd82a32eSJiri Olsa if (!pmu) 942cd82a32eSJiri Olsa return NULL; 943cd82a32eSJiri Olsa 9447ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 94554e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 94654e32dc0SGanapatrao Kulkarni pmu->type = type; 94766ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 94851d54847SJohn Garry if (pmu->is_uncore) 94951d54847SJohn Garry pmu->id = pmu_id(name); 95090a86bdeSJiri Olsa pmu->max_precise = pmu_max_precise(name); 95154e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 9524513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 95366ec1191SMark Rutland 954cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 955a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 9569fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 957cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 958a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 9599bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 960dc0a6202SAdrian Hunter 961dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 962dc0a6202SAdrian Hunter 963cd82a32eSJiri Olsa return pmu; 964cd82a32eSJiri Olsa } 965cd82a32eSJiri Olsa 966b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 967cd82a32eSJiri Olsa { 968cd82a32eSJiri Olsa struct perf_pmu *pmu; 969cd82a32eSJiri Olsa 970cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 971cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 972cd82a32eSJiri Olsa return pmu; 973cd82a32eSJiri Olsa 974cd82a32eSJiri Olsa return NULL; 975cd82a32eSJiri Olsa } 976cd82a32eSJiri Olsa 9773a50dc76SStephane Eranian struct perf_pmu *perf_pmu__find_by_type(unsigned int type) 9783a50dc76SStephane Eranian { 9793a50dc76SStephane Eranian struct perf_pmu *pmu; 9803a50dc76SStephane Eranian 9813a50dc76SStephane Eranian list_for_each_entry(pmu, &pmus, list) 9823a50dc76SStephane Eranian if (pmu->type == type) 9833a50dc76SStephane Eranian return pmu; 9843a50dc76SStephane Eranian 9853a50dc76SStephane Eranian return NULL; 9863a50dc76SStephane Eranian } 9873a50dc76SStephane Eranian 98850a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 98950a9667cSRobert Richter { 99050a9667cSRobert Richter /* 99150a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 99250a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 99350a9667cSRobert Richter */ 99450a9667cSRobert Richter if (!pmu) { 99550a9667cSRobert Richter pmu_read_sysfs(); 99650a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 99750a9667cSRobert Richter } 99850a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 99950a9667cSRobert Richter return pmu; 100050a9667cSRobert Richter return NULL; 100150a9667cSRobert Richter } 100250a9667cSRobert Richter 1003e76026bdSArnaldo Carvalho de Melo struct perf_pmu *evsel__find_pmu(struct evsel *evsel) 1004e12ee9f7SAdrian Hunter { 1005e12ee9f7SAdrian Hunter struct perf_pmu *pmu = NULL; 1006e12ee9f7SAdrian Hunter 1007e12ee9f7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1008e12ee9f7SAdrian Hunter if (pmu->type == evsel->core.attr.type) 1009e12ee9f7SAdrian Hunter break; 1010e12ee9f7SAdrian Hunter } 1011e12ee9f7SAdrian Hunter 1012e12ee9f7SAdrian Hunter return pmu; 1013e12ee9f7SAdrian Hunter } 1014e12ee9f7SAdrian Hunter 101539453ed5SArnaldo Carvalho de Melo bool evsel__is_aux_event(struct evsel *evsel) 1016e12ee9f7SAdrian Hunter { 1017e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 1018e12ee9f7SAdrian Hunter 1019e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 1020e12ee9f7SAdrian Hunter } 1021e12ee9f7SAdrian Hunter 1022b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 1023cd82a32eSJiri Olsa { 1024cd82a32eSJiri Olsa struct perf_pmu *pmu; 1025cd82a32eSJiri Olsa 1026cd82a32eSJiri Olsa /* 1027cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 1028cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 1029cd82a32eSJiri Olsa * the pmu format definitions. 1030cd82a32eSJiri Olsa */ 1031cd82a32eSJiri Olsa pmu = pmu_find(name); 1032cd82a32eSJiri Olsa if (pmu) 1033cd82a32eSJiri Olsa return pmu; 1034cd82a32eSJiri Olsa 1035cd82a32eSJiri Olsa return pmu_lookup(name); 1036cd82a32eSJiri Olsa } 1037cd82a32eSJiri Olsa 10385c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 103909ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 1040cd82a32eSJiri Olsa { 10415c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1042cd82a32eSJiri Olsa 1043cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 1044cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 1045cd82a32eSJiri Olsa return format; 1046cd82a32eSJiri Olsa 1047cd82a32eSJiri Olsa return NULL; 1048cd82a32eSJiri Olsa } 1049cd82a32eSJiri Olsa 105009ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 105109ff6071SAdrian Hunter { 105209ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 105309ff6071SAdrian Hunter __u64 bits = 0; 105409ff6071SAdrian Hunter int fbit; 105509ff6071SAdrian Hunter 105609ff6071SAdrian Hunter if (!format) 105709ff6071SAdrian Hunter return 0; 105809ff6071SAdrian Hunter 105909ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 106009ff6071SAdrian Hunter bits |= 1ULL << fbit; 106109ff6071SAdrian Hunter 106209ff6071SAdrian Hunter return bits; 106309ff6071SAdrian Hunter } 106409ff6071SAdrian Hunter 1065a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1066a1ac7de6SAdrian Hunter { 1067a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1068a1ac7de6SAdrian Hunter 1069a1ac7de6SAdrian Hunter if (!format) 1070a1ac7de6SAdrian Hunter return -1; 1071a1ac7de6SAdrian Hunter 1072a1ac7de6SAdrian Hunter return format->value; 1073a1ac7de6SAdrian Hunter } 1074a1ac7de6SAdrian Hunter 1075cd82a32eSJiri Olsa /* 1076dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 10774d39c89fSIngo Molnar * and unformatted value (value parameter). 1078cd82a32eSJiri Olsa */ 1079dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1080dc0a6202SAdrian Hunter bool zero) 1081cd82a32eSJiri Olsa { 1082cd82a32eSJiri Olsa unsigned long fbit, vbit; 1083cd82a32eSJiri Olsa 1084cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1085cd82a32eSJiri Olsa 1086cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1087cd82a32eSJiri Olsa continue; 1088cd82a32eSJiri Olsa 1089dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1090dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1091dc0a6202SAdrian Hunter else if (zero) 1092dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1093cd82a32eSJiri Olsa } 1094cd82a32eSJiri Olsa } 1095cd82a32eSJiri Olsa 10960efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 10970efe6b67SAdrian Hunter { 10981b9caa10SJiri Olsa int w; 10990efe6b67SAdrian Hunter 11001b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 11011b9caa10SJiri Olsa if (!w) 11021b9caa10SJiri Olsa return 0; 11031b9caa10SJiri Olsa if (w < 64) 11041b9caa10SJiri Olsa return (1ULL << w) - 1; 11051b9caa10SJiri Olsa return -1; 11060efe6b67SAdrian Hunter } 11070efe6b67SAdrian Hunter 1108cd82a32eSJiri Olsa /* 1109688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1110688d4dfcSCody P Schafer * in the remaining terms. 1111688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1112688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1113688d4dfcSCody P Schafer * in a config string) later on in the term list. 1114688d4dfcSCody P Schafer */ 1115688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1116688d4dfcSCody P Schafer struct list_head *head_terms, 1117688d4dfcSCody P Schafer __u64 *value) 1118688d4dfcSCody P Schafer { 1119688d4dfcSCody P Schafer struct parse_events_term *t; 1120688d4dfcSCody P Schafer 1121688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 11222a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 11232a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1124688d4dfcSCody P Schafer t->used = true; 1125688d4dfcSCody P Schafer *value = t->val.num; 1126688d4dfcSCody P Schafer return 0; 1127688d4dfcSCody P Schafer } 1128688d4dfcSCody P Schafer } 1129688d4dfcSCody P Schafer 1130bb963e16SNamhyung Kim if (verbose > 0) 1131688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1132688d4dfcSCody P Schafer 1133688d4dfcSCody P Schafer return -1; 1134688d4dfcSCody P Schafer } 1135688d4dfcSCody P Schafer 1136ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1137e64b020bSJiri Olsa { 1138e64b020bSJiri Olsa struct perf_pmu_format *format; 113911db4e29SMasami Hiramatsu char *str = NULL; 114011db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1141e64b020bSJiri Olsa unsigned i = 0; 1142e64b020bSJiri Olsa 1143ffeb883eSHe Kuang if (!formats) 1144e64b020bSJiri Olsa return NULL; 1145e64b020bSJiri Olsa 1146e64b020bSJiri Olsa /* sysfs exported terms */ 1147ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 114811db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 114911db4e29SMasami Hiramatsu goto error; 1150e64b020bSJiri Olsa 1151ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 115211db4e29SMasami Hiramatsu error: 1153ffeb883eSHe Kuang strbuf_release(&buf); 1154e64b020bSJiri Olsa 1155e64b020bSJiri Olsa return str; 1156e64b020bSJiri Olsa } 1157e64b020bSJiri Olsa 1158688d4dfcSCody P Schafer /* 1159cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 116088aca8d9SCody P Schafer * user input data - term parameter. 1161cd82a32eSJiri Olsa */ 11624ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 11634ac22b48SIan Rogers struct list_head *formats, 1164cd82a32eSJiri Olsa struct perf_event_attr *attr, 1165dc0a6202SAdrian Hunter struct parse_events_term *term, 1166688d4dfcSCody P Schafer struct list_head *head_terms, 1167e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1168cd82a32eSJiri Olsa { 11695c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1170cd82a32eSJiri Olsa __u64 *vp; 11710efe6b67SAdrian Hunter __u64 val, max_val; 1172cd82a32eSJiri Olsa 1173cd82a32eSJiri Olsa /* 1174688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1175688d4dfcSCody P Schafer * skip it in normal eval. 1176688d4dfcSCody P Schafer */ 1177688d4dfcSCody P Schafer if (term->used) 1178688d4dfcSCody P Schafer return 0; 1179688d4dfcSCody P Schafer 1180688d4dfcSCody P Schafer /* 1181cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1182cd82a32eSJiri Olsa * to be done for them. 1183cd82a32eSJiri Olsa */ 1184cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1185cd82a32eSJiri Olsa return 0; 1186cd82a32eSJiri Olsa 1187cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1188688d4dfcSCody P Schafer if (!format) { 1189ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 11904ac22b48SIan Rogers char *unknown_term; 11914ac22b48SIan Rogers char *help_msg; 1192ffeb883eSHe Kuang 11934ac22b48SIan Rogers if (asprintf(&unknown_term, 11944ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 11954ac22b48SIan Rogers term->config, pmu_name) < 0) 11964ac22b48SIan Rogers unknown_term = NULL; 11974ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 11984ac22b48SIan Rogers if (err) { 1199448d732cSIan Rogers parse_events__handle_error(err, term->err_term, 12004ac22b48SIan Rogers unknown_term, 12014ac22b48SIan Rogers help_msg); 12024ac22b48SIan Rogers } else { 12034ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 12044ac22b48SIan Rogers free(unknown_term); 1205e64b020bSJiri Olsa } 12064ac22b48SIan Rogers free(pmu_term); 1207cd82a32eSJiri Olsa return -EINVAL; 1208688d4dfcSCody P Schafer } 1209cd82a32eSJiri Olsa 1210cd82a32eSJiri Olsa switch (format->value) { 1211cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1212cd82a32eSJiri Olsa vp = &attr->config; 1213cd82a32eSJiri Olsa break; 1214cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1215cd82a32eSJiri Olsa vp = &attr->config1; 1216cd82a32eSJiri Olsa break; 1217cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1218cd82a32eSJiri Olsa vp = &attr->config2; 1219cd82a32eSJiri Olsa break; 1220cd82a32eSJiri Olsa default: 1221cd82a32eSJiri Olsa return -EINVAL; 1222cd82a32eSJiri Olsa } 1223cd82a32eSJiri Olsa 122416fa7e82SJiri Olsa /* 1225688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1226688d4dfcSCody P Schafer * using event parameters. 122716fa7e82SJiri Olsa */ 122899e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 122999e7138eSJiri Olsa if (term->no_value && 123099e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 123199e7138eSJiri Olsa if (err) { 1232448d732cSIan Rogers parse_events__handle_error(err, term->err_val, 1233448d732cSIan Rogers strdup("no value assigned for term"), 1234448d732cSIan Rogers NULL); 123599e7138eSJiri Olsa } 123699e7138eSJiri Olsa return -EINVAL; 123799e7138eSJiri Olsa } 123899e7138eSJiri Olsa 1239688d4dfcSCody P Schafer val = term->val.num; 124099e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1241688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1242bb963e16SNamhyung Kim if (verbose > 0) { 1243688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1244688d4dfcSCody P Schafer term->config, term->val.str); 1245e64b020bSJiri Olsa } 1246e64b020bSJiri Olsa if (err) { 1247448d732cSIan Rogers parse_events__handle_error(err, term->err_val, 1248448d732cSIan Rogers strdup("expected numeric value"), 1249448d732cSIan Rogers NULL); 1250e64b020bSJiri Olsa } 1251688d4dfcSCody P Schafer return -EINVAL; 1252688d4dfcSCody P Schafer } 1253688d4dfcSCody P Schafer 1254688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1255688d4dfcSCody P Schafer return -EINVAL; 1256688d4dfcSCody P Schafer } else 1257688d4dfcSCody P Schafer return -EINVAL; 1258688d4dfcSCody P Schafer 12590efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 12600efe6b67SAdrian Hunter if (val > max_val) { 12610efe6b67SAdrian Hunter if (err) { 1262448d732cSIan Rogers char *err_str; 1263448d732cSIan Rogers 1264448d732cSIan Rogers parse_events__handle_error(err, term->err_val, 1265448d732cSIan Rogers asprintf(&err_str, 12660efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1267448d732cSIan Rogers (unsigned long long)max_val) < 0 1268448d732cSIan Rogers ? strdup("value too big for format") 1269448d732cSIan Rogers : err_str, 1270448d732cSIan Rogers NULL); 12710efe6b67SAdrian Hunter return -EINVAL; 12720efe6b67SAdrian Hunter } 12730efe6b67SAdrian Hunter /* 12740efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 12750efe6b67SAdrian Hunter * silently truncated. 12760efe6b67SAdrian Hunter */ 12770efe6b67SAdrian Hunter } 12780efe6b67SAdrian Hunter 1279688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1280cd82a32eSJiri Olsa return 0; 1281cd82a32eSJiri Olsa } 1282cd82a32eSJiri Olsa 12834ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1284cff7f956SJiri Olsa struct perf_event_attr *attr, 1285dc0a6202SAdrian Hunter struct list_head *head_terms, 1286e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1287cd82a32eSJiri Olsa { 12886cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1289cd82a32eSJiri Olsa 1290688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 12914ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1292e64b020bSJiri Olsa zero, err)) 1293cd82a32eSJiri Olsa return -EINVAL; 1294688d4dfcSCody P Schafer } 1295cd82a32eSJiri Olsa 1296cd82a32eSJiri Olsa return 0; 1297cd82a32eSJiri Olsa } 1298cd82a32eSJiri Olsa 1299cd82a32eSJiri Olsa /* 1300cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1301cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1302cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1303cd82a32eSJiri Olsa */ 1304cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1305e64b020bSJiri Olsa struct list_head *head_terms, 1306e64b020bSJiri Olsa struct parse_events_error *err) 1307cd82a32eSJiri Olsa { 1308dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1309dc0a6202SAdrian Hunter 1310cd82a32eSJiri Olsa attr->type = pmu->type; 13114ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 13124ac22b48SIan Rogers head_terms, zero, err); 1313cd82a32eSJiri Olsa } 1314cd82a32eSJiri Olsa 13155c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 13166cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1317a6146d50SZheng Yan { 13185c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1319a6146d50SZheng Yan char *name; 1320a6146d50SZheng Yan 1321a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1322a6146d50SZheng Yan return NULL; 1323a6146d50SZheng Yan 1324a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1325a6146d50SZheng Yan if (term->val.num != 1) 1326a6146d50SZheng Yan return NULL; 1327a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1328a6146d50SZheng Yan return NULL; 1329a6146d50SZheng Yan name = term->config; 1330a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1331a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1332a6146d50SZheng Yan return NULL; 1333a6146d50SZheng Yan name = term->val.str; 1334a6146d50SZheng Yan } else { 1335a6146d50SZheng Yan return NULL; 1336a6146d50SZheng Yan } 1337a6146d50SZheng Yan 1338a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1339a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1340a6146d50SZheng Yan return alias; 1341a6146d50SZheng Yan } 1342a6146d50SZheng Yan return NULL; 1343a6146d50SZheng Yan } 1344a6146d50SZheng Yan 1345410136f5SStephane Eranian 13461d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 13471d9e446bSJiri Olsa struct perf_pmu_info *info) 1348410136f5SStephane Eranian { 1349410136f5SStephane Eranian /* 1350410136f5SStephane Eranian * Only one term in event definition can 13511d9e446bSJiri Olsa * define unit, scale and snapshot, fail 13521d9e446bSJiri Olsa * if there's more than one. 1353410136f5SStephane Eranian */ 1354b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 13551d9e446bSJiri Olsa (info->scale && alias->scale) || 13561d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1357410136f5SStephane Eranian return -EINVAL; 1358410136f5SStephane Eranian 1359b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 13601d9e446bSJiri Olsa info->unit = alias->unit; 1361410136f5SStephane Eranian 1362410136f5SStephane Eranian if (alias->scale) 13631d9e446bSJiri Olsa info->scale = alias->scale; 13641d9e446bSJiri Olsa 13651d9e446bSJiri Olsa if (alias->snapshot) 13661d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1367410136f5SStephane Eranian 1368410136f5SStephane Eranian return 0; 1369410136f5SStephane Eranian } 1370410136f5SStephane Eranian 1371a6146d50SZheng Yan /* 1372a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1373a6146d50SZheng Yan * defined for the alias 1374a6146d50SZheng Yan */ 1375410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 137646441bdcSMatt Fleming struct perf_pmu_info *info) 1377a6146d50SZheng Yan { 13786cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 13795c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1380a6146d50SZheng Yan int ret; 1381a6146d50SZheng Yan 1382044330c1SMatt Fleming info->per_pkg = false; 1383044330c1SMatt Fleming 13848a398897SStephane Eranian /* 13858a398897SStephane Eranian * Mark unit and scale as not set 13868a398897SStephane Eranian * (different from default values, see below) 13878a398897SStephane Eranian */ 138846441bdcSMatt Fleming info->unit = NULL; 138946441bdcSMatt Fleming info->scale = 0.0; 13901d9e446bSJiri Olsa info->snapshot = false; 139137932c18SAndi Kleen info->metric_expr = NULL; 139296284814SAndi Kleen info->metric_name = NULL; 1393410136f5SStephane Eranian 1394a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1395a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1396a6146d50SZheng Yan if (!alias) 1397a6146d50SZheng Yan continue; 1398a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1399a6146d50SZheng Yan if (ret) 1400a6146d50SZheng Yan return ret; 1401410136f5SStephane Eranian 14021d9e446bSJiri Olsa ret = check_info_data(alias, info); 1403410136f5SStephane Eranian if (ret) 1404410136f5SStephane Eranian return ret; 1405410136f5SStephane Eranian 1406044330c1SMatt Fleming if (alias->per_pkg) 1407044330c1SMatt Fleming info->per_pkg = true; 140837932c18SAndi Kleen info->metric_expr = alias->metric_expr; 140996284814SAndi Kleen info->metric_name = alias->metric_name; 1410044330c1SMatt Fleming 1411e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 14121dc92556SIan Rogers parse_events_term__delete(term); 1413a6146d50SZheng Yan } 14148a398897SStephane Eranian 14158a398897SStephane Eranian /* 14168a398897SStephane Eranian * if no unit or scale found in aliases, then 14178a398897SStephane Eranian * set defaults as for evsel 14188a398897SStephane Eranian * unit cannot left to NULL 14198a398897SStephane Eranian */ 142046441bdcSMatt Fleming if (info->unit == NULL) 142146441bdcSMatt Fleming info->unit = ""; 14228a398897SStephane Eranian 142346441bdcSMatt Fleming if (info->scale == 0.0) 142446441bdcSMatt Fleming info->scale = 1.0; 14258a398897SStephane Eranian 1426a6146d50SZheng Yan return 0; 1427a6146d50SZheng Yan } 1428a6146d50SZheng Yan 1429cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1430cd82a32eSJiri Olsa int config, unsigned long *bits) 1431cd82a32eSJiri Olsa { 14325c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1433cd82a32eSJiri Olsa 1434cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1435cd82a32eSJiri Olsa if (!format) 1436cd82a32eSJiri Olsa return -ENOMEM; 1437cd82a32eSJiri Olsa 1438cd82a32eSJiri Olsa format->name = strdup(name); 1439cd82a32eSJiri Olsa format->value = config; 1440cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1441cd82a32eSJiri Olsa 1442cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1443cd82a32eSJiri Olsa return 0; 1444cd82a32eSJiri Olsa } 1445cd82a32eSJiri Olsa 1446cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1447cd82a32eSJiri Olsa { 1448cd82a32eSJiri Olsa long b; 1449cd82a32eSJiri Olsa 1450cd82a32eSJiri Olsa if (!to) 1451cd82a32eSJiri Olsa to = from; 1452cd82a32eSJiri Olsa 145315268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1454cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1455cd82a32eSJiri Olsa set_bit(b, bits); 1456cd82a32eSJiri Olsa } 1457dc098b35SAndi Kleen 1458d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1459d26383dcSNamhyung Kim { 1460d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1461d26383dcSNamhyung Kim 1462d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1463d26383dcSNamhyung Kim list_del(&fmt->list); 1464d26383dcSNamhyung Kim free(fmt->name); 1465d26383dcSNamhyung Kim free(fmt); 1466d26383dcSNamhyung Kim } 1467d26383dcSNamhyung Kim } 1468d26383dcSNamhyung Kim 1469aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1470aaea3617SCody P Schafer { 1471aaea3617SCody P Schafer if (b > a) 1472aaea3617SCody P Schafer return 0; 1473aaea3617SCody P Schafer return a - b; 1474aaea3617SCody P Schafer } 1475aaea3617SCody P Schafer 1476dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1477dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1478dc098b35SAndi Kleen { 1479aaea3617SCody P Schafer struct parse_events_term *term; 1480aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1481aaea3617SCody P Schafer 1482aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1483aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1484aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1485aaea3617SCody P Schafer ",%s=%s", term->config, 1486aaea3617SCody P Schafer term->val.str); 1487aaea3617SCody P Schafer } 1488aaea3617SCody P Schafer 1489aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1490aaea3617SCody P Schafer buf[used] = '/'; 1491aaea3617SCody P Schafer used++; 1492aaea3617SCody P Schafer } 1493aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1494aaea3617SCody P Schafer buf[used] = '\0'; 1495aaea3617SCody P Schafer used++; 1496aaea3617SCody P Schafer } else 1497aaea3617SCody P Schafer buf[len - 1] = '\0'; 1498aaea3617SCody P Schafer 1499dc098b35SAndi Kleen return buf; 1500dc098b35SAndi Kleen } 1501dc098b35SAndi Kleen 1502dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1503dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1504dc098b35SAndi Kleen { 1505dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1506dc098b35SAndi Kleen return buf; 1507dc098b35SAndi Kleen } 1508dc098b35SAndi Kleen 1509dd5f1036SAndi Kleen struct sevent { 151008e60ed1SAndi Kleen char *name; 151108e60ed1SAndi Kleen char *desc; 1512dd5f1036SAndi Kleen char *topic; 1513f2361024SAndi Kleen char *str; 1514f2361024SAndi Kleen char *pmu; 15157f372a63SAndi Kleen char *metric_expr; 151696284814SAndi Kleen char *metric_name; 1517ce0dc7d2SJohn Garry int is_cpu; 151808e60ed1SAndi Kleen }; 151908e60ed1SAndi Kleen 1520dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1521dc098b35SAndi Kleen { 1522dd5f1036SAndi Kleen const struct sevent *as = a; 1523dd5f1036SAndi Kleen const struct sevent *bs = b; 152408e60ed1SAndi Kleen 152508e60ed1SAndi Kleen /* Put extra events last */ 152608e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 152708e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1528dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1529dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1530dd5f1036SAndi Kleen 1531dd5f1036SAndi Kleen if (n) 1532dd5f1036SAndi Kleen return n; 1533dd5f1036SAndi Kleen } 1534ce0dc7d2SJohn Garry 1535ce0dc7d2SJohn Garry /* Order CPU core events to be first */ 1536ce0dc7d2SJohn Garry if (as->is_cpu != bs->is_cpu) 1537ce0dc7d2SJohn Garry return bs->is_cpu - as->is_cpu; 1538ce0dc7d2SJohn Garry 153908e60ed1SAndi Kleen return strcmp(as->name, bs->name); 154008e60ed1SAndi Kleen } 154108e60ed1SAndi Kleen 154208e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 154308e60ed1SAndi Kleen { 154408e60ed1SAndi Kleen int column = start; 154508e60ed1SAndi Kleen int n; 154608e60ed1SAndi Kleen 154708e60ed1SAndi Kleen while (*s) { 154808e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 154908e60ed1SAndi Kleen 155008e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 155108e60ed1SAndi Kleen printf("\n%*s", start, ""); 155208e60ed1SAndi Kleen column = start + corr; 155308e60ed1SAndi Kleen } 155408e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 155508e60ed1SAndi Kleen if (n <= 0) 155608e60ed1SAndi Kleen break; 155708e60ed1SAndi Kleen s += wlen; 155808e60ed1SAndi Kleen column += n; 155932858480SArnaldo Carvalho de Melo s = skip_spaces(s); 156008e60ed1SAndi Kleen } 1561dc098b35SAndi Kleen } 1562dc098b35SAndi Kleen 1563d504fae9SJohn Garry bool is_pmu_core(const char *name) 1564d504fae9SJohn Garry { 1565d504fae9SJohn Garry return !strcmp(name, "cpu") || is_arm_pmu_core(name); 1566d504fae9SJohn Garry } 1567d504fae9SJohn Garry 1568c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1569a7f6c8c8SJin Yao bool long_desc, bool details_flag, bool deprecated) 1570dc098b35SAndi Kleen { 1571dc098b35SAndi Kleen struct perf_pmu *pmu; 1572dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1573dc098b35SAndi Kleen char buf[1024]; 1574dc098b35SAndi Kleen int printed = 0; 1575dc098b35SAndi Kleen int len, j; 1576dd5f1036SAndi Kleen struct sevent *aliases; 157708e60ed1SAndi Kleen int numdesc = 0; 157861eb2eb4SAndi Kleen int columns = pager_get_columns(); 1579dd5f1036SAndi Kleen char *topic = NULL; 1580dc098b35SAndi Kleen 1581dc098b35SAndi Kleen pmu = NULL; 1582dc098b35SAndi Kleen len = 0; 158342634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1584dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1585dc098b35SAndi Kleen len++; 158642634bc7SAdrian Hunter if (pmu->selectable) 158742634bc7SAdrian Hunter len++; 158842634bc7SAdrian Hunter } 1589dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1590dc098b35SAndi Kleen if (!aliases) 15917e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1592dc098b35SAndi Kleen pmu = NULL; 1593dc098b35SAndi Kleen j = 0; 159442634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1595dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 159608e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 159708e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1598c1b4745bSJohn Garry bool is_cpu = is_pmu_core(pmu->name); 1599dc098b35SAndi Kleen 1600a7f6c8c8SJin Yao if (alias->deprecated && !deprecated) 1601a7f6c8c8SJin Yao continue; 1602a7f6c8c8SJin Yao 1603dc098b35SAndi Kleen if (event_glob != NULL && 160438d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 160538d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 160667bdc35fSAndi Kleen event_glob)) || 160767bdc35fSAndi Kleen (alias->topic && 160867bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1609dc098b35SAndi Kleen continue; 16107e4772dcSArnaldo Carvalho de Melo 161108e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 16127e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 16137e4772dcSArnaldo Carvalho de Melo 161408e60ed1SAndi Kleen aliases[j].name = name; 161508e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 161608e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 161708e60ed1SAndi Kleen sizeof(buf), 161808e60ed1SAndi Kleen pmu, alias); 161908e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 162008e60ed1SAndi Kleen if (!aliases[j].name) 16217e4772dcSArnaldo Carvalho de Melo goto out_enomem; 162208e60ed1SAndi Kleen 1623c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1624c8d6828aSSukadev Bhattiprolu alias->desc; 1625dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1626f2361024SAndi Kleen aliases[j].str = alias->str; 1627f2361024SAndi Kleen aliases[j].pmu = pmu->name; 16287f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 162996284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1630ce0dc7d2SJohn Garry aliases[j].is_cpu = is_cpu; 1631dc098b35SAndi Kleen j++; 1632dc098b35SAndi Kleen } 1633fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1634fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 16357e4772dcSArnaldo Carvalho de Melo char *s; 16367e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 16377e4772dcSArnaldo Carvalho de Melo goto out_enomem; 163808e60ed1SAndi Kleen aliases[j].name = s; 163942634bc7SAdrian Hunter j++; 164042634bc7SAdrian Hunter } 164142634bc7SAdrian Hunter } 1642dc098b35SAndi Kleen len = j; 1643dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1644dc098b35SAndi Kleen for (j = 0; j < len; j++) { 164515b22ed3SAndi Kleen /* Skip duplicates */ 164615b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 164715b22ed3SAndi Kleen continue; 1648dc098b35SAndi Kleen if (name_only) { 164908e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1650dc098b35SAndi Kleen continue; 1651dc098b35SAndi Kleen } 16521c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 165308e60ed1SAndi Kleen if (numdesc++ == 0) 165408e60ed1SAndi Kleen printf("\n"); 1655dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1656dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1657dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1658dd5f1036SAndi Kleen aliases[j].topic); 1659dd5f1036SAndi Kleen topic = aliases[j].topic; 1660dd5f1036SAndi Kleen } 166108e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 166208e60ed1SAndi Kleen printf("%*s", 8, "["); 166308e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 166408e60ed1SAndi Kleen printf("]\n"); 1665bf874fcfSAndi Kleen if (details_flag) { 16667f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 166796284814SAndi Kleen if (aliases[j].metric_name) 166896284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 16697f372a63SAndi Kleen if (aliases[j].metric_expr) 16707f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 16717f372a63SAndi Kleen putchar('\n'); 16727f372a63SAndi Kleen } 167308e60ed1SAndi Kleen } else 167408e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1675dc098b35SAndi Kleen printed++; 1676dc098b35SAndi Kleen } 1677dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1678dc098b35SAndi Kleen printf("\n"); 16797e4772dcSArnaldo Carvalho de Melo out_free: 16807e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 168108e60ed1SAndi Kleen zfree(&aliases[j].name); 16827e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 16837e4772dcSArnaldo Carvalho de Melo return; 16847e4772dcSArnaldo Carvalho de Melo 16857e4772dcSArnaldo Carvalho de Melo out_enomem: 16867e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 16877e4772dcSArnaldo Carvalho de Melo if (aliases) 16887e4772dcSArnaldo Carvalho de Melo goto out_free; 1689dc098b35SAndi Kleen } 16904cabc3d1SAndi Kleen 16914cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 16924cabc3d1SAndi Kleen { 16934cabc3d1SAndi Kleen struct perf_pmu *pmu; 16944cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 16954cabc3d1SAndi Kleen 16964cabc3d1SAndi Kleen pmu = NULL; 16974cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 16984cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 16994cabc3d1SAndi Kleen continue; 17004cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 17014cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 17024cabc3d1SAndi Kleen return true; 17034cabc3d1SAndi Kleen } 17044cabc3d1SAndi Kleen return false; 17054cabc3d1SAndi Kleen } 17067d4bdab5SAdrian Hunter 17077d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 17087d4bdab5SAdrian Hunter { 17097d4bdab5SAdrian Hunter char path[PATH_MAX]; 17107d4bdab5SAdrian Hunter const char *sysfs; 17117d4bdab5SAdrian Hunter 17127d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 17137d4bdab5SAdrian Hunter if (!sysfs) 17147d4bdab5SAdrian Hunter return NULL; 17157d4bdab5SAdrian Hunter 17167d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 17177d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 1718d9664582SAndi Kleen if (!file_available(path)) 17197d4bdab5SAdrian Hunter return NULL; 17207d4bdab5SAdrian Hunter return fopen(path, "r"); 17217d4bdab5SAdrian Hunter } 17227d4bdab5SAdrian Hunter 17237d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 17247d4bdab5SAdrian Hunter ...) 17257d4bdab5SAdrian Hunter { 17267d4bdab5SAdrian Hunter va_list args; 17277d4bdab5SAdrian Hunter FILE *file; 17287d4bdab5SAdrian Hunter int ret = EOF; 17297d4bdab5SAdrian Hunter 17307d4bdab5SAdrian Hunter va_start(args, fmt); 17317d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 17327d4bdab5SAdrian Hunter if (file) { 17337d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 17347d4bdab5SAdrian Hunter fclose(file); 17357d4bdab5SAdrian Hunter } 17367d4bdab5SAdrian Hunter va_end(args); 17377d4bdab5SAdrian Hunter return ret; 17387d4bdab5SAdrian Hunter } 17399fbc61f8SKan Liang 17409fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 17419fbc61f8SKan Liang { 17429fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 17439fbc61f8SKan Liang 17449fbc61f8SKan Liang if (!caps) 17459fbc61f8SKan Liang return -ENOMEM; 17469fbc61f8SKan Liang 17479fbc61f8SKan Liang caps->name = strdup(name); 17489fbc61f8SKan Liang if (!caps->name) 17499fbc61f8SKan Liang goto free_caps; 17509fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 17519fbc61f8SKan Liang if (!caps->value) 17529fbc61f8SKan Liang goto free_name; 17539fbc61f8SKan Liang list_add_tail(&caps->list, list); 17549fbc61f8SKan Liang return 0; 17559fbc61f8SKan Liang 17569fbc61f8SKan Liang free_name: 17579fbc61f8SKan Liang zfree(caps->name); 17589fbc61f8SKan Liang free_caps: 17599fbc61f8SKan Liang free(caps); 17609fbc61f8SKan Liang 17619fbc61f8SKan Liang return -ENOMEM; 17629fbc61f8SKan Liang } 17639fbc61f8SKan Liang 17649fbc61f8SKan Liang /* 17659fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 17669fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 17679fbc61f8SKan Liang * Return the number of capabilities 17689fbc61f8SKan Liang */ 17699fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 17709fbc61f8SKan Liang { 17719fbc61f8SKan Liang struct stat st; 17729fbc61f8SKan Liang char caps_path[PATH_MAX]; 17739fbc61f8SKan Liang const char *sysfs = sysfs__mountpoint(); 17749fbc61f8SKan Liang DIR *caps_dir; 17759fbc61f8SKan Liang struct dirent *evt_ent; 17769fbc61f8SKan Liang int nr_caps = 0; 17779fbc61f8SKan Liang 17789fbc61f8SKan Liang if (!sysfs) 17799fbc61f8SKan Liang return -1; 17809fbc61f8SKan Liang 17819fbc61f8SKan Liang snprintf(caps_path, PATH_MAX, 17829fbc61f8SKan Liang "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name); 17839fbc61f8SKan Liang 17849fbc61f8SKan Liang if (stat(caps_path, &st) < 0) 17859fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 17869fbc61f8SKan Liang 17879fbc61f8SKan Liang caps_dir = opendir(caps_path); 17889fbc61f8SKan Liang if (!caps_dir) 17899fbc61f8SKan Liang return -EINVAL; 17909fbc61f8SKan Liang 17919fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 17929fbc61f8SKan Liang char path[PATH_MAX + NAME_MAX + 1]; 17939fbc61f8SKan Liang char *name = evt_ent->d_name; 17949fbc61f8SKan Liang char value[128]; 17959fbc61f8SKan Liang FILE *file; 17969fbc61f8SKan Liang 17979fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 17989fbc61f8SKan Liang continue; 17999fbc61f8SKan Liang 18009fbc61f8SKan Liang snprintf(path, sizeof(path), "%s/%s", caps_path, name); 18019fbc61f8SKan Liang 18029fbc61f8SKan Liang file = fopen(path, "r"); 18039fbc61f8SKan Liang if (!file) 18049fbc61f8SKan Liang continue; 18059fbc61f8SKan Liang 18069fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 18079fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 18089fbc61f8SKan Liang fclose(file); 18099fbc61f8SKan Liang continue; 18109fbc61f8SKan Liang } 18119fbc61f8SKan Liang 18129fbc61f8SKan Liang nr_caps++; 18139fbc61f8SKan Liang fclose(file); 18149fbc61f8SKan Liang } 18159fbc61f8SKan Liang 18169fbc61f8SKan Liang closedir(caps_dir); 18179fbc61f8SKan Liang 18189fbc61f8SKan Liang return nr_caps; 18199fbc61f8SKan Liang } 1820e4064776SJin Yao 1821e4064776SJin Yao void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 1822e4064776SJin Yao char *name) 1823e4064776SJin Yao { 1824e4064776SJin Yao struct perf_pmu_format *format; 1825e4064776SJin Yao __u64 masks = 0, bits; 1826e4064776SJin Yao char buf[100]; 1827e4064776SJin Yao unsigned int i; 1828e4064776SJin Yao 1829e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1830e4064776SJin Yao if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG) 1831e4064776SJin Yao continue; 1832e4064776SJin Yao 1833e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1834e4064776SJin Yao masks |= 1ULL << i; 1835e4064776SJin Yao } 1836e4064776SJin Yao 1837e4064776SJin Yao /* 1838e4064776SJin Yao * Kernel doesn't export any valid format bits. 1839e4064776SJin Yao */ 1840e4064776SJin Yao if (masks == 0) 1841e4064776SJin Yao return; 1842e4064776SJin Yao 1843e4064776SJin Yao bits = config & ~masks; 1844e4064776SJin Yao if (bits == 0) 1845e4064776SJin Yao return; 1846e4064776SJin Yao 1847e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1848e4064776SJin Yao 1849e4064776SJin Yao pr_warning("WARNING: event '%s' not valid (bits %s of config " 1850e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1851e4064776SJin Yao name ?: "N/A", buf, config); 1852e4064776SJin Yao } 1853