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 29ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 30ab1bf653SArnaldo Carvalho de Melo char *name; 31ab1bf653SArnaldo Carvalho de Melo int value; 32ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 33ab1bf653SArnaldo Carvalho de Melo struct list_head list; 34ab1bf653SArnaldo Carvalho de Melo }; 35ab1bf653SArnaldo Carvalho de Melo 36cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 37cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 38cd82a32eSJiri Olsa 39cd82a32eSJiri Olsa static LIST_HEAD(pmus); 40cd82a32eSJiri Olsa 41cd82a32eSJiri Olsa /* 42cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 43cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 44cd82a32eSJiri Olsa */ 45cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 46cd82a32eSJiri Olsa { 47cd82a32eSJiri Olsa struct dirent *evt_ent; 48cd82a32eSJiri Olsa DIR *format_dir; 49cd82a32eSJiri Olsa int ret = 0; 50cd82a32eSJiri Olsa 51cd82a32eSJiri Olsa format_dir = opendir(dir); 52cd82a32eSJiri Olsa if (!format_dir) 53cd82a32eSJiri Olsa return -EINVAL; 54cd82a32eSJiri Olsa 55cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 56cd82a32eSJiri Olsa char path[PATH_MAX]; 57cd82a32eSJiri Olsa char *name = evt_ent->d_name; 58cd82a32eSJiri Olsa FILE *file; 59cd82a32eSJiri Olsa 60cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 61cd82a32eSJiri Olsa continue; 62cd82a32eSJiri Olsa 63cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 64cd82a32eSJiri Olsa 65cd82a32eSJiri Olsa ret = -EINVAL; 66cd82a32eSJiri Olsa file = fopen(path, "r"); 67cd82a32eSJiri Olsa if (!file) 68cd82a32eSJiri Olsa break; 69cd82a32eSJiri Olsa 70cd82a32eSJiri Olsa perf_pmu_in = file; 71cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 72cd82a32eSJiri Olsa fclose(file); 73cd82a32eSJiri Olsa } 74cd82a32eSJiri Olsa 75cd82a32eSJiri Olsa closedir(format_dir); 76cd82a32eSJiri Olsa return ret; 77cd82a32eSJiri Olsa } 78cd82a32eSJiri Olsa 79cd82a32eSJiri Olsa /* 80cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 81cd82a32eSJiri Olsa * located at: 82cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 83cd82a32eSJiri Olsa */ 84b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 85cd82a32eSJiri Olsa { 86cd82a32eSJiri Olsa char path[PATH_MAX]; 87cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 88cd82a32eSJiri Olsa 89cd82a32eSJiri Olsa if (!sysfs) 90cd82a32eSJiri Olsa return -1; 91cd82a32eSJiri Olsa 92cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9350a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 94cd82a32eSJiri Olsa 95d9664582SAndi Kleen if (!file_available(path)) 96d9664582SAndi Kleen return 0; 97cd82a32eSJiri Olsa 98cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 99cd82a32eSJiri Olsa return -1; 100cd82a32eSJiri Olsa 101cd82a32eSJiri Olsa return 0; 102cd82a32eSJiri Olsa } 103cd82a32eSJiri Olsa 104a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 105d02fc6bcSAndi Kleen { 106d02fc6bcSAndi Kleen char *lc; 107d02fc6bcSAndi Kleen int ret = 0; 108d02fc6bcSAndi Kleen 109d02fc6bcSAndi Kleen /* 110d02fc6bcSAndi Kleen * save current locale 111d02fc6bcSAndi Kleen */ 112d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 113d02fc6bcSAndi Kleen 114d02fc6bcSAndi Kleen /* 115d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 116d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 117d02fc6bcSAndi Kleen * call below. 118d02fc6bcSAndi Kleen */ 119d02fc6bcSAndi Kleen lc = strdup(lc); 120d02fc6bcSAndi Kleen if (!lc) { 121d02fc6bcSAndi Kleen ret = -ENOMEM; 122d02fc6bcSAndi Kleen goto out; 123d02fc6bcSAndi Kleen } 124d02fc6bcSAndi Kleen 125d02fc6bcSAndi Kleen /* 126d02fc6bcSAndi Kleen * force to C locale to ensure kernel 127d02fc6bcSAndi Kleen * scale string is converted correctly. 128d02fc6bcSAndi Kleen * kernel uses default C locale. 129d02fc6bcSAndi Kleen */ 130d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 131d02fc6bcSAndi Kleen 132d02fc6bcSAndi Kleen *sval = strtod(scale, end); 133d02fc6bcSAndi Kleen 134d02fc6bcSAndi Kleen out: 135d02fc6bcSAndi Kleen /* restore locale */ 136d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 137d02fc6bcSAndi Kleen free(lc); 138d02fc6bcSAndi Kleen return ret; 139d02fc6bcSAndi Kleen } 140d02fc6bcSAndi Kleen 141410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 142410136f5SStephane Eranian { 143410136f5SStephane Eranian struct stat st; 144410136f5SStephane Eranian ssize_t sret; 145410136f5SStephane Eranian char scale[128]; 146410136f5SStephane Eranian int fd, ret = -1; 147410136f5SStephane Eranian char path[PATH_MAX]; 148410136f5SStephane Eranian 14911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 150410136f5SStephane Eranian 151410136f5SStephane Eranian fd = open(path, O_RDONLY); 152410136f5SStephane Eranian if (fd == -1) 153410136f5SStephane Eranian return -1; 154410136f5SStephane Eranian 155410136f5SStephane Eranian if (fstat(fd, &st) < 0) 156410136f5SStephane Eranian goto error; 157410136f5SStephane Eranian 158410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 159410136f5SStephane Eranian if (sret < 0) 160410136f5SStephane Eranian goto error; 161410136f5SStephane Eranian 1629ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1639ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1649ecae065SMadhavan Srinivasan else 165410136f5SStephane Eranian scale[sret] = '\0'; 1669ecae065SMadhavan Srinivasan 167a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 168410136f5SStephane Eranian error: 169410136f5SStephane Eranian close(fd); 170410136f5SStephane Eranian return ret; 171410136f5SStephane Eranian } 172410136f5SStephane Eranian 173410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 174410136f5SStephane Eranian { 175410136f5SStephane Eranian char path[PATH_MAX]; 176410136f5SStephane Eranian ssize_t sret; 177410136f5SStephane Eranian int fd; 178410136f5SStephane Eranian 17911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 180410136f5SStephane Eranian 181410136f5SStephane Eranian fd = open(path, O_RDONLY); 182410136f5SStephane Eranian if (fd == -1) 183410136f5SStephane Eranian return -1; 184410136f5SStephane Eranian 185410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 186410136f5SStephane Eranian if (sret < 0) 187410136f5SStephane Eranian goto error; 188410136f5SStephane Eranian 189410136f5SStephane Eranian close(fd); 190410136f5SStephane Eranian 1919ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1929ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1939ecae065SMadhavan Srinivasan else 194410136f5SStephane Eranian alias->unit[sret] = '\0'; 195410136f5SStephane Eranian 196410136f5SStephane Eranian return 0; 197410136f5SStephane Eranian error: 198410136f5SStephane Eranian close(fd); 199410136f5SStephane Eranian alias->unit[0] = '\0'; 200410136f5SStephane Eranian return -1; 201410136f5SStephane Eranian } 202410136f5SStephane Eranian 203044330c1SMatt Fleming static int 204044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 205044330c1SMatt Fleming { 206044330c1SMatt Fleming char path[PATH_MAX]; 207044330c1SMatt Fleming int fd; 208044330c1SMatt Fleming 20911a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 210044330c1SMatt Fleming 211044330c1SMatt Fleming fd = open(path, O_RDONLY); 212044330c1SMatt Fleming if (fd == -1) 213044330c1SMatt Fleming return -1; 214044330c1SMatt Fleming 215044330c1SMatt Fleming close(fd); 216044330c1SMatt Fleming 217044330c1SMatt Fleming alias->per_pkg = true; 218044330c1SMatt Fleming return 0; 219044330c1SMatt Fleming } 220044330c1SMatt Fleming 2211d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2221d9e446bSJiri Olsa char *dir, char *name) 2231d9e446bSJiri Olsa { 2241d9e446bSJiri Olsa char path[PATH_MAX]; 2251d9e446bSJiri Olsa int fd; 2261d9e446bSJiri Olsa 22711a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2281d9e446bSJiri Olsa 2291d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2301d9e446bSJiri Olsa if (fd == -1) 2311d9e446bSJiri Olsa return -1; 2321d9e446bSJiri Olsa 2331d9e446bSJiri Olsa alias->snapshot = true; 2341d9e446bSJiri Olsa close(fd); 2351d9e446bSJiri Olsa return 0; 2361d9e446bSJiri Olsa } 2371d9e446bSJiri Olsa 2386dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2396dde6429SThomas Richter char **new_str) 2406dde6429SThomas Richter { 2416dde6429SThomas Richter if (!*old_str) 2426dde6429SThomas Richter goto set_new; 2436dde6429SThomas Richter 2446dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2456dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2466dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2476dde6429SThomas Richter name, field); 2486dde6429SThomas Richter zfree(old_str); 2496dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2506dde6429SThomas Richter return; 2516dde6429SThomas Richter set_new: 2526dde6429SThomas Richter *old_str = *new_str; 2536dde6429SThomas Richter *new_str = NULL; 2546dde6429SThomas Richter } 2556dde6429SThomas Richter 2566dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2576dde6429SThomas Richter struct perf_pmu_alias *newalias) 2586dde6429SThomas Richter { 2596dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2606dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2616dde6429SThomas Richter &newalias->long_desc); 2626dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2636dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, 2646dde6429SThomas Richter &newalias->metric_expr); 2656dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, 2666dde6429SThomas Richter &newalias->metric_name); 2676dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2686dde6429SThomas Richter old->scale = newalias->scale; 2696dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2706dde6429SThomas Richter old->snapshot = newalias->snapshot; 2716dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2726dde6429SThomas Richter } 2736dde6429SThomas Richter 2746dde6429SThomas Richter /* Delete an alias entry. */ 2756dde6429SThomas Richter static void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2766dde6429SThomas Richter { 2776dde6429SThomas Richter zfree(&newalias->name); 2786dde6429SThomas Richter zfree(&newalias->desc); 2796dde6429SThomas Richter zfree(&newalias->long_desc); 2806dde6429SThomas Richter zfree(&newalias->topic); 2816dde6429SThomas Richter zfree(&newalias->str); 2826dde6429SThomas Richter zfree(&newalias->metric_expr); 2836dde6429SThomas Richter zfree(&newalias->metric_name); 2846dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 2856dde6429SThomas Richter free(newalias); 2866dde6429SThomas Richter } 2876dde6429SThomas Richter 2886dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 2896dde6429SThomas Richter * present merge both of them to combine all information. 2906dde6429SThomas Richter */ 2916dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 2926dde6429SThomas Richter struct list_head *alist) 2936dde6429SThomas Richter { 2946dde6429SThomas Richter struct perf_pmu_alias *a; 2956dde6429SThomas Richter 2966dde6429SThomas Richter list_for_each_entry(a, alist, list) { 2976dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 2986dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 2996dde6429SThomas Richter perf_pmu_free_alias(newalias); 3006dde6429SThomas Richter return true; 3016dde6429SThomas Richter } 3026dde6429SThomas Richter } 3036dde6429SThomas Richter return false; 3046dde6429SThomas Richter } 3056dde6429SThomas Richter 30670c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 307fedb2b51SAndi Kleen char *desc, char *val, 308fedb2b51SAndi Kleen char *long_desc, char *topic, 30900636c3bSAndi Kleen char *unit, char *perpkg, 31096284814SAndi Kleen char *metric_expr, 311a7f6c8c8SJin Yao char *metric_name, 312a7f6c8c8SJin Yao char *deprecated) 313a6146d50SZheng Yan { 3140c24d6fbSThomas Richter struct parse_events_term *term; 3155c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 316a6146d50SZheng Yan int ret; 317fedb2b51SAndi Kleen int num; 3180c24d6fbSThomas Richter char newval[256]; 319a6146d50SZheng Yan 320a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 321a6146d50SZheng Yan if (!alias) 322a6146d50SZheng Yan return -ENOMEM; 323a6146d50SZheng Yan 324a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 325410136f5SStephane Eranian alias->scale = 1.0; 326410136f5SStephane Eranian alias->unit[0] = '\0'; 327044330c1SMatt Fleming alias->per_pkg = false; 32884530920SStephane Eranian alias->snapshot = false; 329a7f6c8c8SJin Yao alias->deprecated = false; 330410136f5SStephane Eranian 33170c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 332a6146d50SZheng Yan if (ret) { 33370c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 334a6146d50SZheng Yan free(alias); 335a6146d50SZheng Yan return ret; 336a6146d50SZheng Yan } 337a6146d50SZheng Yan 3380c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3390c24d6fbSThomas Richter * platforms have terms specified as 3400c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3410c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3420c24d6fbSThomas Richter * 3430c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3440c24d6fbSThomas Richter */ 3450c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3460c24d6fbSThomas Richter ret = 0; 3470c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3480c24d6fbSThomas Richter if (ret) 3490c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3500c24d6fbSThomas Richter ","); 3510c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3520c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3530c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3540c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3550c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3560c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3570c24d6fbSThomas Richter } 3580c24d6fbSThomas Richter 359a6146d50SZheng Yan alias->name = strdup(name); 36070c646e0SSukadev Bhattiprolu if (dir) { 361410136f5SStephane Eranian /* 362410136f5SStephane Eranian * load unit name and scale if available 363410136f5SStephane Eranian */ 364410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 365410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 366044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 3671d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 36870c646e0SSukadev Bhattiprolu } 369410136f5SStephane Eranian 37000636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 37196284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 37208e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 373c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 374c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 375dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 376fedb2b51SAndi Kleen if (unit) { 377a55ab7c4SJin Yao if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) 378fedb2b51SAndi Kleen return -1; 379fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 380fedb2b51SAndi Kleen } 381fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 3820c24d6fbSThomas Richter alias->str = strdup(newval); 383f2361024SAndi Kleen 384a7f6c8c8SJin Yao if (deprecated) 385a7f6c8c8SJin Yao alias->deprecated = true; 386a7f6c8c8SJin Yao 3876dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 388a6146d50SZheng Yan list_add_tail(&alias->list, list); 389410136f5SStephane Eranian 390a6146d50SZheng Yan return 0; 391a6146d50SZheng Yan } 392a6146d50SZheng Yan 39370c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 39470c646e0SSukadev Bhattiprolu { 39570c646e0SSukadev Bhattiprolu char buf[256]; 39670c646e0SSukadev Bhattiprolu int ret; 39770c646e0SSukadev Bhattiprolu 39870c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 39970c646e0SSukadev Bhattiprolu if (ret == 0) 40070c646e0SSukadev Bhattiprolu return -EINVAL; 40170c646e0SSukadev Bhattiprolu 40270c646e0SSukadev Bhattiprolu buf[ret] = 0; 40370c646e0SSukadev Bhattiprolu 404ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 40513c230abSArnaldo Carvalho de Melo strim(buf); 406ea23ac73SThomas Richter 407fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 408a7f6c8c8SJin Yao NULL, NULL, NULL, NULL); 40970c646e0SSukadev Bhattiprolu } 41070c646e0SSukadev Bhattiprolu 41146441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 41246441bdcSMatt Fleming { 41346441bdcSMatt Fleming size_t len; 41446441bdcSMatt Fleming 41546441bdcSMatt Fleming len = strlen(name); 41646441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 41746441bdcSMatt Fleming return true; 41846441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 41946441bdcSMatt Fleming return true; 420044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 421044330c1SMatt Fleming return true; 4221d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4231d9e446bSJiri Olsa return true; 42446441bdcSMatt Fleming 42546441bdcSMatt Fleming return false; 42646441bdcSMatt Fleming } 42746441bdcSMatt Fleming 428a6146d50SZheng Yan /* 429a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 430a6146d50SZheng Yan * specified in 'dir' parameter. 431a6146d50SZheng Yan */ 432a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 433a6146d50SZheng Yan { 434a6146d50SZheng Yan struct dirent *evt_ent; 435a6146d50SZheng Yan DIR *event_dir; 436a6146d50SZheng Yan 437a6146d50SZheng Yan event_dir = opendir(dir); 438a6146d50SZheng Yan if (!event_dir) 439a6146d50SZheng Yan return -EINVAL; 440a6146d50SZheng Yan 441940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 442a6146d50SZheng Yan char path[PATH_MAX]; 443a6146d50SZheng Yan char *name = evt_ent->d_name; 444a6146d50SZheng Yan FILE *file; 445a6146d50SZheng Yan 446a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 447a6146d50SZheng Yan continue; 448a6146d50SZheng Yan 449410136f5SStephane Eranian /* 45046441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 451410136f5SStephane Eranian */ 45246441bdcSMatt Fleming if (pmu_alias_info_file(name)) 453410136f5SStephane Eranian continue; 454410136f5SStephane Eranian 45577f18153SJiri Olsa scnprintf(path, PATH_MAX, "%s/%s", dir, name); 456a6146d50SZheng Yan 457a6146d50SZheng Yan file = fopen(path, "r"); 458940db6dcSAndi Kleen if (!file) { 459940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 460940db6dcSAndi Kleen continue; 461940db6dcSAndi Kleen } 462410136f5SStephane Eranian 463940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 464940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 465a6146d50SZheng Yan fclose(file); 466a6146d50SZheng Yan } 467a6146d50SZheng Yan 468a6146d50SZheng Yan closedir(event_dir); 469940db6dcSAndi Kleen return 0; 470a6146d50SZheng Yan } 471a6146d50SZheng Yan 472a6146d50SZheng Yan /* 473a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 474a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 475a6146d50SZheng Yan */ 476b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 477a6146d50SZheng Yan { 478a6146d50SZheng Yan char path[PATH_MAX]; 479cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 480a6146d50SZheng Yan 481a6146d50SZheng Yan if (!sysfs) 482a6146d50SZheng Yan return -1; 483a6146d50SZheng Yan 484a6146d50SZheng Yan snprintf(path, PATH_MAX, 485a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 486a6146d50SZheng Yan 487d9664582SAndi Kleen if (!file_available(path)) 488d9664582SAndi Kleen return 0; 489a6146d50SZheng Yan 490a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 491a6146d50SZheng Yan return -1; 492a6146d50SZheng Yan 493a6146d50SZheng Yan return 0; 494a6146d50SZheng Yan } 495a6146d50SZheng Yan 4965c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 497a6146d50SZheng Yan struct list_head *terms) 498a6146d50SZheng Yan { 4997c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 500a6146d50SZheng Yan LIST_HEAD(list); 501a6146d50SZheng Yan int ret; 502a6146d50SZheng Yan 503a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5047c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 505a6146d50SZheng Yan if (ret) { 506682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 507a6146d50SZheng Yan return ret; 508a6146d50SZheng Yan } 509c2f1ceadSAndi Kleen /* 510c2f1ceadSAndi Kleen * Weak terms don't override command line options, 511c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 512c2f1ceadSAndi Kleen */ 513c2f1ceadSAndi Kleen cloned->weak = true; 5147c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 515a6146d50SZheng Yan } 516a6146d50SZheng Yan list_splice(&list, terms); 517a6146d50SZheng Yan return 0; 518a6146d50SZheng Yan } 519a6146d50SZheng Yan 520cd82a32eSJiri Olsa /* 521cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 522cd82a32eSJiri Olsa * located at: 523cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 524cd82a32eSJiri Olsa */ 525b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 526cd82a32eSJiri Olsa { 527cd82a32eSJiri Olsa char path[PATH_MAX]; 528cd82a32eSJiri Olsa FILE *file; 529cd82a32eSJiri Olsa int ret = 0; 530cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 531cd82a32eSJiri Olsa 532cd82a32eSJiri Olsa if (!sysfs) 533cd82a32eSJiri Olsa return -1; 534cd82a32eSJiri Olsa 535cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 53650a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 537cd82a32eSJiri Olsa 538d9664582SAndi Kleen if (access(path, R_OK) < 0) 539cd82a32eSJiri Olsa return -1; 540cd82a32eSJiri Olsa 541cd82a32eSJiri Olsa file = fopen(path, "r"); 542cd82a32eSJiri Olsa if (!file) 543cd82a32eSJiri Olsa return -EINVAL; 544cd82a32eSJiri Olsa 545cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 546cd82a32eSJiri Olsa ret = -1; 547cd82a32eSJiri Olsa 548cd82a32eSJiri Olsa fclose(file); 549cd82a32eSJiri Olsa return ret; 550cd82a32eSJiri Olsa } 551cd82a32eSJiri Olsa 55250a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 55350a9667cSRobert Richter static void pmu_read_sysfs(void) 55450a9667cSRobert Richter { 55550a9667cSRobert Richter char path[PATH_MAX]; 55650a9667cSRobert Richter DIR *dir; 55750a9667cSRobert Richter struct dirent *dent; 558cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 55950a9667cSRobert Richter 56050a9667cSRobert Richter if (!sysfs) 56150a9667cSRobert Richter return; 56250a9667cSRobert Richter 56350a9667cSRobert Richter snprintf(path, PATH_MAX, 56450a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 56550a9667cSRobert Richter 56650a9667cSRobert Richter dir = opendir(path); 56750a9667cSRobert Richter if (!dir) 56850a9667cSRobert Richter return; 56950a9667cSRobert Richter 57050a9667cSRobert Richter while ((dent = readdir(dir))) { 57150a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 57250a9667cSRobert Richter continue; 57350a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 57450a9667cSRobert Richter perf_pmu__find(dent->d_name); 57550a9667cSRobert Richter } 57650a9667cSRobert Richter 57750a9667cSRobert Richter closedir(dir); 57850a9667cSRobert Richter } 57950a9667cSRobert Richter 580f854839bSJiri Olsa static struct perf_cpu_map *__pmu_cpumask(const char *path) 58166ec1191SMark Rutland { 58266ec1191SMark Rutland FILE *file; 583f854839bSJiri Olsa struct perf_cpu_map *cpus; 58466ec1191SMark Rutland 58566ec1191SMark Rutland file = fopen(path, "r"); 58666ec1191SMark Rutland if (!file) 58766ec1191SMark Rutland return NULL; 58866ec1191SMark Rutland 5899c3516d1SJiri Olsa cpus = perf_cpu_map__read(file); 59066ec1191SMark Rutland fclose(file); 59166ec1191SMark Rutland return cpus; 59266ec1191SMark Rutland } 59366ec1191SMark Rutland 59466ec1191SMark Rutland /* 59566ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 59666ec1191SMark Rutland * may have a "cpus" file. 59766ec1191SMark Rutland */ 59866ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 59966ec1191SMark Rutland #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 60066ec1191SMark Rutland 601f854839bSJiri Olsa static struct perf_cpu_map *pmu_cpumask(const char *name) 6027ae92e74SYan, Zheng { 6037ae92e74SYan, Zheng char path[PATH_MAX]; 604f854839bSJiri Olsa struct perf_cpu_map *cpus; 605cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 6067e3fcffeSMark Rutland const char *templates[] = { 60766ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 60866ec1191SMark Rutland CPUS_TEMPLATE_CPU, 6097e3fcffeSMark Rutland NULL 6107e3fcffeSMark Rutland }; 6117e3fcffeSMark Rutland const char **template; 6127ae92e74SYan, Zheng 6137ae92e74SYan, Zheng if (!sysfs) 6147ae92e74SYan, Zheng return NULL; 6157ae92e74SYan, Zheng 6167e3fcffeSMark Rutland for (template = templates; *template; template++) { 6177e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 61866ec1191SMark Rutland cpus = __pmu_cpumask(path); 61966ec1191SMark Rutland if (cpus) 62066ec1191SMark Rutland return cpus; 6217e3fcffeSMark Rutland } 6227ae92e74SYan, Zheng 6237ae92e74SYan, Zheng return NULL; 62466ec1191SMark Rutland } 6257ae92e74SYan, Zheng 62666ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 62766ec1191SMark Rutland { 62866ec1191SMark Rutland char path[PATH_MAX]; 629d9664582SAndi Kleen const char *sysfs; 6307ae92e74SYan, Zheng 631d9664582SAndi Kleen sysfs = sysfs__mountpoint(); 63266ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 633d9664582SAndi Kleen return file_available(path); 6347ae92e74SYan, Zheng } 6357ae92e74SYan, Zheng 636933f82ffSSukadev Bhattiprolu /* 63714b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 638292c34c1SKan Liang * platforms. 639292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 64014b22ae0SGanapatrao Kulkarni */ 641292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 64214b22ae0SGanapatrao Kulkarni { 64314b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 64414b22ae0SGanapatrao Kulkarni const char *sysfs = sysfs__mountpoint(); 64514b22ae0SGanapatrao Kulkarni 64614b22ae0SGanapatrao Kulkarni if (!sysfs) 64714b22ae0SGanapatrao Kulkarni return 0; 64814b22ae0SGanapatrao Kulkarni 64914b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (specific to arm) */ 65014b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", 65114b22ae0SGanapatrao Kulkarni sysfs, name); 652d9664582SAndi Kleen return file_available(path); 65314b22ae0SGanapatrao Kulkarni } 65414b22ae0SGanapatrao Kulkarni 65554e32dc0SGanapatrao Kulkarni static char *perf_pmu__getcpuid(struct perf_pmu *pmu) 656d77ade9fSAndi Kleen { 657d77ade9fSAndi Kleen char *cpuid; 658d77ade9fSAndi Kleen static bool printed; 659d77ade9fSAndi Kleen 660d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 661d77ade9fSAndi Kleen if (cpuid) 662d77ade9fSAndi Kleen cpuid = strdup(cpuid); 663d77ade9fSAndi Kleen if (!cpuid) 66454e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 665d77ade9fSAndi Kleen if (!cpuid) 666d77ade9fSAndi Kleen return NULL; 667d77ade9fSAndi Kleen 668d77ade9fSAndi Kleen if (!printed) { 669d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 670d77ade9fSAndi Kleen printed = true; 671d77ade9fSAndi Kleen } 672d77ade9fSAndi Kleen return cpuid; 673d77ade9fSAndi Kleen } 674d77ade9fSAndi Kleen 67554e32dc0SGanapatrao Kulkarni struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu) 676d77ade9fSAndi Kleen { 677d77ade9fSAndi Kleen struct pmu_events_map *map; 67854e32dc0SGanapatrao Kulkarni char *cpuid = perf_pmu__getcpuid(pmu); 679d77ade9fSAndi Kleen int i; 680d77ade9fSAndi Kleen 681de3d0f12SGanapatrao Kulkarni /* on some platforms which uses cpus map, cpuid can be NULL for 682de3d0f12SGanapatrao Kulkarni * PMUs other than CORE PMUs. 683de3d0f12SGanapatrao Kulkarni */ 684de3d0f12SGanapatrao Kulkarni if (!cpuid) 685de3d0f12SGanapatrao Kulkarni return NULL; 686de3d0f12SGanapatrao Kulkarni 687d77ade9fSAndi Kleen i = 0; 688d77ade9fSAndi Kleen for (;;) { 689d77ade9fSAndi Kleen map = &pmu_events_map[i++]; 690d77ade9fSAndi Kleen if (!map->table) { 691d77ade9fSAndi Kleen map = NULL; 692d77ade9fSAndi Kleen break; 693d77ade9fSAndi Kleen } 694d77ade9fSAndi Kleen 6954cb7d3ecSThomas Richter if (!strcmp_cpuid_str(map->cpuid, cpuid)) 696d77ade9fSAndi Kleen break; 697d77ade9fSAndi Kleen } 698d77ade9fSAndi Kleen free(cpuid); 699d77ade9fSAndi Kleen return map; 700d77ade9fSAndi Kleen } 701d77ade9fSAndi Kleen 7025b9a5000SJohn Garry bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 703730670b1SJohn Garry { 704730670b1SJohn Garry char *tmp = NULL, *tok, *str; 705730670b1SJohn Garry bool res; 706730670b1SJohn Garry 707730670b1SJohn Garry str = strdup(pmu_name); 708730670b1SJohn Garry if (!str) 709730670b1SJohn Garry return false; 710730670b1SJohn Garry 711730670b1SJohn Garry /* 712730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 713730670b1SJohn Garry */ 714730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 715730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 716730670b1SJohn Garry res = false; 717730670b1SJohn Garry goto out; 718730670b1SJohn Garry } 719730670b1SJohn Garry 720730670b1SJohn Garry /* 721730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 722730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 723730670b1SJohn Garry * 724730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 725730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 726730670b1SJohn Garry * "pmunameY". 727730670b1SJohn Garry */ 728730670b1SJohn Garry for (; tok; name += strlen(tok), tok = strtok_r(NULL, ",", &tmp)) { 729730670b1SJohn Garry name = strstr(name, tok); 730730670b1SJohn Garry if (!name) { 731730670b1SJohn Garry res = false; 732730670b1SJohn Garry goto out; 733730670b1SJohn Garry } 734730670b1SJohn Garry } 735730670b1SJohn Garry 736730670b1SJohn Garry res = true; 737730670b1SJohn Garry out: 738730670b1SJohn Garry free(str); 739730670b1SJohn Garry return res; 740730670b1SJohn Garry } 741730670b1SJohn Garry 742933f82ffSSukadev Bhattiprolu /* 743933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 744933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 745933f82ffSSukadev Bhattiprolu * as aliases. 746933f82ffSSukadev Bhattiprolu */ 747e45ad701SJohn Garry void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu, 748e45ad701SJohn Garry struct pmu_events_map *map) 749933f82ffSSukadev Bhattiprolu { 750933f82ffSSukadev Bhattiprolu int i; 75154e32dc0SGanapatrao Kulkarni const char *name = pmu->name; 752933f82ffSSukadev Bhattiprolu /* 753933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 754933f82ffSSukadev Bhattiprolu */ 755933f82ffSSukadev Bhattiprolu i = 0; 756933f82ffSSukadev Bhattiprolu while (1) { 757599ee18fSJohn Garry const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu"; 758599ee18fSJohn Garry struct pmu_event *pe = &map->table[i++]; 759599ee18fSJohn Garry const char *pname = pe->pmu ? pe->pmu : cpu_name; 760fedb2b51SAndi Kleen 761b18f3e36SAndi Kleen if (!pe->name) { 762b18f3e36SAndi Kleen if (pe->metric_group || pe->metric_name) 763b18f3e36SAndi Kleen continue; 764933f82ffSSukadev Bhattiprolu break; 765b18f3e36SAndi Kleen } 766933f82ffSSukadev Bhattiprolu 767e94d6b7fSKan Liang if (pmu_is_uncore(name) && 768730670b1SJohn Garry pmu_uncore_alias_match(pname, name)) 769e94d6b7fSKan Liang goto new_alias; 770e94d6b7fSKan Liang 771ea1fa48cSThomas Richter if (strcmp(pname, name)) 77214b22ae0SGanapatrao Kulkarni continue; 773fedb2b51SAndi Kleen 774e94d6b7fSKan Liang new_alias: 775933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 776933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 777c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 778fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 77900636c3bSAndi Kleen (char *)pe->unit, (char *)pe->perpkg, 78096284814SAndi Kleen (char *)pe->metric_expr, 781a7f6c8c8SJin Yao (char *)pe->metric_name, 782a7f6c8c8SJin Yao (char *)pe->deprecated); 783933f82ffSSukadev Bhattiprolu } 784933f82ffSSukadev Bhattiprolu } 785933f82ffSSukadev Bhattiprolu 786e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 787e45ad701SJohn Garry { 788e45ad701SJohn Garry struct pmu_events_map *map; 789e45ad701SJohn Garry 790e45ad701SJohn Garry map = perf_pmu__find_map(pmu); 791e45ad701SJohn Garry if (!map) 792e45ad701SJohn Garry return; 793e45ad701SJohn Garry 794e45ad701SJohn Garry pmu_add_cpu_aliases_map(head, pmu, map); 795e45ad701SJohn Garry } 796e45ad701SJohn Garry 797c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 798dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 799dc0a6202SAdrian Hunter { 800dc0a6202SAdrian Hunter return NULL; 801dc0a6202SAdrian Hunter } 802dc0a6202SAdrian Hunter 80390a86bdeSJiri Olsa static int pmu_max_precise(const char *name) 80490a86bdeSJiri Olsa { 80590a86bdeSJiri Olsa char path[PATH_MAX]; 80690a86bdeSJiri Olsa int max_precise = -1; 80790a86bdeSJiri Olsa 80890a86bdeSJiri Olsa scnprintf(path, PATH_MAX, 80990a86bdeSJiri Olsa "bus/event_source/devices/%s/caps/max_precise", 81090a86bdeSJiri Olsa name); 81190a86bdeSJiri Olsa 81290a86bdeSJiri Olsa sysfs__read_int(path, &max_precise); 81390a86bdeSJiri Olsa return max_precise; 81490a86bdeSJiri Olsa } 81590a86bdeSJiri Olsa 816b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 817cd82a32eSJiri Olsa { 818cd82a32eSJiri Olsa struct perf_pmu *pmu; 819cd82a32eSJiri Olsa LIST_HEAD(format); 820a6146d50SZheng Yan LIST_HEAD(aliases); 821cd82a32eSJiri Olsa __u32 type; 822cd82a32eSJiri Olsa 823cd82a32eSJiri Olsa /* 824cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 825cd82a32eSJiri Olsa * type value and format definitions. Load both right 826cd82a32eSJiri Olsa * now. 827cd82a32eSJiri Olsa */ 828cd82a32eSJiri Olsa if (pmu_format(name, &format)) 829cd82a32eSJiri Olsa return NULL; 830cd82a32eSJiri Olsa 83115b22ed3SAndi Kleen /* 83215b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 83315b22ed3SAndi Kleen */ 83415b22ed3SAndi Kleen if (pmu_type(name, &type)) 83515b22ed3SAndi Kleen return NULL; 83615b22ed3SAndi Kleen 8373fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 8383fded963SJiri Olsa return NULL; 8393fded963SJiri Olsa 840cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 841cd82a32eSJiri Olsa if (!pmu) 842cd82a32eSJiri Olsa return NULL; 843cd82a32eSJiri Olsa 8447ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 84554e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 84654e32dc0SGanapatrao Kulkarni pmu->type = type; 84766ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 84890a86bdeSJiri Olsa pmu->max_precise = pmu_max_precise(name); 84954e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 85066ec1191SMark Rutland 851cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 852a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 8539fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 854cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 855a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 8569bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 857dc0a6202SAdrian Hunter 858dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 859dc0a6202SAdrian Hunter 860cd82a32eSJiri Olsa return pmu; 861cd82a32eSJiri Olsa } 862cd82a32eSJiri Olsa 863b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 864cd82a32eSJiri Olsa { 865cd82a32eSJiri Olsa struct perf_pmu *pmu; 866cd82a32eSJiri Olsa 867cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 868cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 869cd82a32eSJiri Olsa return pmu; 870cd82a32eSJiri Olsa 871cd82a32eSJiri Olsa return NULL; 872cd82a32eSJiri Olsa } 873cd82a32eSJiri Olsa 87450a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 87550a9667cSRobert Richter { 87650a9667cSRobert Richter /* 87750a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 87850a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 87950a9667cSRobert Richter */ 88050a9667cSRobert Richter if (!pmu) { 88150a9667cSRobert Richter pmu_read_sysfs(); 88250a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 88350a9667cSRobert Richter } 88450a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 88550a9667cSRobert Richter return pmu; 88650a9667cSRobert Richter return NULL; 88750a9667cSRobert Richter } 88850a9667cSRobert Richter 889e12ee9f7SAdrian Hunter struct perf_pmu *perf_evsel__find_pmu(struct evsel *evsel) 890e12ee9f7SAdrian Hunter { 891e12ee9f7SAdrian Hunter struct perf_pmu *pmu = NULL; 892e12ee9f7SAdrian Hunter 893e12ee9f7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 894e12ee9f7SAdrian Hunter if (pmu->type == evsel->core.attr.type) 895e12ee9f7SAdrian Hunter break; 896e12ee9f7SAdrian Hunter } 897e12ee9f7SAdrian Hunter 898e12ee9f7SAdrian Hunter return pmu; 899e12ee9f7SAdrian Hunter } 900e12ee9f7SAdrian Hunter 901e12ee9f7SAdrian Hunter bool perf_evsel__is_aux_event(struct evsel *evsel) 902e12ee9f7SAdrian Hunter { 903e12ee9f7SAdrian Hunter struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); 904e12ee9f7SAdrian Hunter 905e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 906e12ee9f7SAdrian Hunter } 907e12ee9f7SAdrian Hunter 908b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 909cd82a32eSJiri Olsa { 910cd82a32eSJiri Olsa struct perf_pmu *pmu; 911cd82a32eSJiri Olsa 912cd82a32eSJiri Olsa /* 913cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 914cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 915cd82a32eSJiri Olsa * the pmu format definitions. 916cd82a32eSJiri Olsa */ 917cd82a32eSJiri Olsa pmu = pmu_find(name); 918cd82a32eSJiri Olsa if (pmu) 919cd82a32eSJiri Olsa return pmu; 920cd82a32eSJiri Olsa 921cd82a32eSJiri Olsa return pmu_lookup(name); 922cd82a32eSJiri Olsa } 923cd82a32eSJiri Olsa 9245c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 92509ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 926cd82a32eSJiri Olsa { 9275c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 928cd82a32eSJiri Olsa 929cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 930cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 931cd82a32eSJiri Olsa return format; 932cd82a32eSJiri Olsa 933cd82a32eSJiri Olsa return NULL; 934cd82a32eSJiri Olsa } 935cd82a32eSJiri Olsa 93609ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 93709ff6071SAdrian Hunter { 93809ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 93909ff6071SAdrian Hunter __u64 bits = 0; 94009ff6071SAdrian Hunter int fbit; 94109ff6071SAdrian Hunter 94209ff6071SAdrian Hunter if (!format) 94309ff6071SAdrian Hunter return 0; 94409ff6071SAdrian Hunter 94509ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 94609ff6071SAdrian Hunter bits |= 1ULL << fbit; 94709ff6071SAdrian Hunter 94809ff6071SAdrian Hunter return bits; 94909ff6071SAdrian Hunter } 95009ff6071SAdrian Hunter 951a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 952a1ac7de6SAdrian Hunter { 953a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 954a1ac7de6SAdrian Hunter 955a1ac7de6SAdrian Hunter if (!format) 956a1ac7de6SAdrian Hunter return -1; 957a1ac7de6SAdrian Hunter 958a1ac7de6SAdrian Hunter return format->value; 959a1ac7de6SAdrian Hunter } 960a1ac7de6SAdrian Hunter 961cd82a32eSJiri Olsa /* 962dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 963cd82a32eSJiri Olsa * and unformated value (value parameter). 964cd82a32eSJiri Olsa */ 965dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 966dc0a6202SAdrian Hunter bool zero) 967cd82a32eSJiri Olsa { 968cd82a32eSJiri Olsa unsigned long fbit, vbit; 969cd82a32eSJiri Olsa 970cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 971cd82a32eSJiri Olsa 972cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 973cd82a32eSJiri Olsa continue; 974cd82a32eSJiri Olsa 975dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 976dc0a6202SAdrian Hunter *v |= (1llu << fbit); 977dc0a6202SAdrian Hunter else if (zero) 978dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 979cd82a32eSJiri Olsa } 980cd82a32eSJiri Olsa } 981cd82a32eSJiri Olsa 9820efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 9830efe6b67SAdrian Hunter { 9841b9caa10SJiri Olsa int w; 9850efe6b67SAdrian Hunter 9861b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 9871b9caa10SJiri Olsa if (!w) 9881b9caa10SJiri Olsa return 0; 9891b9caa10SJiri Olsa if (w < 64) 9901b9caa10SJiri Olsa return (1ULL << w) - 1; 9911b9caa10SJiri Olsa return -1; 9920efe6b67SAdrian Hunter } 9930efe6b67SAdrian Hunter 994cd82a32eSJiri Olsa /* 995688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 996688d4dfcSCody P Schafer * in the remaining terms. 997688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 998688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 999688d4dfcSCody P Schafer * in a config string) later on in the term list. 1000688d4dfcSCody P Schafer */ 1001688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1002688d4dfcSCody P Schafer struct list_head *head_terms, 1003688d4dfcSCody P Schafer __u64 *value) 1004688d4dfcSCody P Schafer { 1005688d4dfcSCody P Schafer struct parse_events_term *t; 1006688d4dfcSCody P Schafer 1007688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 10082a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 10092a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1010688d4dfcSCody P Schafer t->used = true; 1011688d4dfcSCody P Schafer *value = t->val.num; 1012688d4dfcSCody P Schafer return 0; 1013688d4dfcSCody P Schafer } 1014688d4dfcSCody P Schafer } 1015688d4dfcSCody P Schafer 1016bb963e16SNamhyung Kim if (verbose > 0) 1017688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1018688d4dfcSCody P Schafer 1019688d4dfcSCody P Schafer return -1; 1020688d4dfcSCody P Schafer } 1021688d4dfcSCody P Schafer 1022ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1023e64b020bSJiri Olsa { 1024e64b020bSJiri Olsa struct perf_pmu_format *format; 102511db4e29SMasami Hiramatsu char *str = NULL; 102611db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1027e64b020bSJiri Olsa unsigned i = 0; 1028e64b020bSJiri Olsa 1029ffeb883eSHe Kuang if (!formats) 1030e64b020bSJiri Olsa return NULL; 1031e64b020bSJiri Olsa 1032e64b020bSJiri Olsa /* sysfs exported terms */ 1033ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 103411db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 103511db4e29SMasami Hiramatsu goto error; 1036e64b020bSJiri Olsa 1037ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 103811db4e29SMasami Hiramatsu error: 1039ffeb883eSHe Kuang strbuf_release(&buf); 1040e64b020bSJiri Olsa 1041e64b020bSJiri Olsa return str; 1042e64b020bSJiri Olsa } 1043e64b020bSJiri Olsa 1044688d4dfcSCody P Schafer /* 1045cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 104688aca8d9SCody P Schafer * user input data - term parameter. 1047cd82a32eSJiri Olsa */ 1048cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 1049cd82a32eSJiri Olsa struct perf_event_attr *attr, 1050dc0a6202SAdrian Hunter struct parse_events_term *term, 1051688d4dfcSCody P Schafer struct list_head *head_terms, 1052e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1053cd82a32eSJiri Olsa { 10545c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1055cd82a32eSJiri Olsa __u64 *vp; 10560efe6b67SAdrian Hunter __u64 val, max_val; 1057cd82a32eSJiri Olsa 1058cd82a32eSJiri Olsa /* 1059688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1060688d4dfcSCody P Schafer * skip it in normal eval. 1061688d4dfcSCody P Schafer */ 1062688d4dfcSCody P Schafer if (term->used) 1063688d4dfcSCody P Schafer return 0; 1064688d4dfcSCody P Schafer 1065688d4dfcSCody P Schafer /* 1066cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1067cd82a32eSJiri Olsa * to be done for them. 1068cd82a32eSJiri Olsa */ 1069cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1070cd82a32eSJiri Olsa return 0; 1071cd82a32eSJiri Olsa 1072cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1073688d4dfcSCody P Schafer if (!format) { 1074bb963e16SNamhyung Kim if (verbose > 0) 1075688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 1076e64b020bSJiri Olsa if (err) { 1077ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 1078ffeb883eSHe Kuang 1079448d732cSIan Rogers parse_events__handle_error(err, term->err_term, 1080448d732cSIan Rogers strdup("unknown term"), 1081448d732cSIan Rogers parse_events_formats_error_string(pmu_term)); 1082ffeb883eSHe Kuang free(pmu_term); 1083e64b020bSJiri Olsa } 1084cd82a32eSJiri Olsa return -EINVAL; 1085688d4dfcSCody P Schafer } 1086cd82a32eSJiri Olsa 1087cd82a32eSJiri Olsa switch (format->value) { 1088cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1089cd82a32eSJiri Olsa vp = &attr->config; 1090cd82a32eSJiri Olsa break; 1091cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1092cd82a32eSJiri Olsa vp = &attr->config1; 1093cd82a32eSJiri Olsa break; 1094cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1095cd82a32eSJiri Olsa vp = &attr->config2; 1096cd82a32eSJiri Olsa break; 1097cd82a32eSJiri Olsa default: 1098cd82a32eSJiri Olsa return -EINVAL; 1099cd82a32eSJiri Olsa } 1100cd82a32eSJiri Olsa 110116fa7e82SJiri Olsa /* 1102688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1103688d4dfcSCody P Schafer * using event parameters. 110416fa7e82SJiri Olsa */ 110599e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 110699e7138eSJiri Olsa if (term->no_value && 110799e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 110899e7138eSJiri Olsa if (err) { 1109448d732cSIan Rogers parse_events__handle_error(err, term->err_val, 1110448d732cSIan Rogers strdup("no value assigned for term"), 1111448d732cSIan Rogers NULL); 111299e7138eSJiri Olsa } 111399e7138eSJiri Olsa return -EINVAL; 111499e7138eSJiri Olsa } 111599e7138eSJiri Olsa 1116688d4dfcSCody P Schafer val = term->val.num; 111799e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1118688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1119bb963e16SNamhyung Kim if (verbose > 0) { 1120688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1121688d4dfcSCody P Schafer term->config, term->val.str); 1122e64b020bSJiri Olsa } 1123e64b020bSJiri Olsa if (err) { 1124448d732cSIan Rogers parse_events__handle_error(err, term->err_val, 1125448d732cSIan Rogers strdup("expected numeric value"), 1126448d732cSIan Rogers NULL); 1127e64b020bSJiri Olsa } 1128688d4dfcSCody P Schafer return -EINVAL; 1129688d4dfcSCody P Schafer } 1130688d4dfcSCody P Schafer 1131688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1132688d4dfcSCody P Schafer return -EINVAL; 1133688d4dfcSCody P Schafer } else 1134688d4dfcSCody P Schafer return -EINVAL; 1135688d4dfcSCody P Schafer 11360efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 11370efe6b67SAdrian Hunter if (val > max_val) { 11380efe6b67SAdrian Hunter if (err) { 1139448d732cSIan Rogers char *err_str; 1140448d732cSIan Rogers 1141448d732cSIan Rogers parse_events__handle_error(err, term->err_val, 1142448d732cSIan Rogers asprintf(&err_str, 11430efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1144448d732cSIan Rogers (unsigned long long)max_val) < 0 1145448d732cSIan Rogers ? strdup("value too big for format") 1146448d732cSIan Rogers : err_str, 1147448d732cSIan Rogers NULL); 11480efe6b67SAdrian Hunter return -EINVAL; 11490efe6b67SAdrian Hunter } 11500efe6b67SAdrian Hunter /* 11510efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 11520efe6b67SAdrian Hunter * silently truncated. 11530efe6b67SAdrian Hunter */ 11540efe6b67SAdrian Hunter } 11550efe6b67SAdrian Hunter 1156688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1157cd82a32eSJiri Olsa return 0; 1158cd82a32eSJiri Olsa } 1159cd82a32eSJiri Olsa 1160cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 1161cff7f956SJiri Olsa struct perf_event_attr *attr, 1162dc0a6202SAdrian Hunter struct list_head *head_terms, 1163e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1164cd82a32eSJiri Olsa { 11656cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1166cd82a32eSJiri Olsa 1167688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 1168e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 1169e64b020bSJiri Olsa zero, err)) 1170cd82a32eSJiri Olsa return -EINVAL; 1171688d4dfcSCody P Schafer } 1172cd82a32eSJiri Olsa 1173cd82a32eSJiri Olsa return 0; 1174cd82a32eSJiri Olsa } 1175cd82a32eSJiri Olsa 1176cd82a32eSJiri Olsa /* 1177cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1178cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1179cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1180cd82a32eSJiri Olsa */ 1181cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1182e64b020bSJiri Olsa struct list_head *head_terms, 1183e64b020bSJiri Olsa struct parse_events_error *err) 1184cd82a32eSJiri Olsa { 1185dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1186dc0a6202SAdrian Hunter 1187cd82a32eSJiri Olsa attr->type = pmu->type; 1188e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 1189e64b020bSJiri Olsa zero, err); 1190cd82a32eSJiri Olsa } 1191cd82a32eSJiri Olsa 11925c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 11936cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1194a6146d50SZheng Yan { 11955c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1196a6146d50SZheng Yan char *name; 1197a6146d50SZheng Yan 1198a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1199a6146d50SZheng Yan return NULL; 1200a6146d50SZheng Yan 1201a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1202a6146d50SZheng Yan if (term->val.num != 1) 1203a6146d50SZheng Yan return NULL; 1204a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1205a6146d50SZheng Yan return NULL; 1206a6146d50SZheng Yan name = term->config; 1207a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1208a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1209a6146d50SZheng Yan return NULL; 1210a6146d50SZheng Yan name = term->val.str; 1211a6146d50SZheng Yan } else { 1212a6146d50SZheng Yan return NULL; 1213a6146d50SZheng Yan } 1214a6146d50SZheng Yan 1215a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1216a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1217a6146d50SZheng Yan return alias; 1218a6146d50SZheng Yan } 1219a6146d50SZheng Yan return NULL; 1220a6146d50SZheng Yan } 1221a6146d50SZheng Yan 1222410136f5SStephane Eranian 12231d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 12241d9e446bSJiri Olsa struct perf_pmu_info *info) 1225410136f5SStephane Eranian { 1226410136f5SStephane Eranian /* 1227410136f5SStephane Eranian * Only one term in event definition can 12281d9e446bSJiri Olsa * define unit, scale and snapshot, fail 12291d9e446bSJiri Olsa * if there's more than one. 1230410136f5SStephane Eranian */ 1231b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 12321d9e446bSJiri Olsa (info->scale && alias->scale) || 12331d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1234410136f5SStephane Eranian return -EINVAL; 1235410136f5SStephane Eranian 1236b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 12371d9e446bSJiri Olsa info->unit = alias->unit; 1238410136f5SStephane Eranian 1239410136f5SStephane Eranian if (alias->scale) 12401d9e446bSJiri Olsa info->scale = alias->scale; 12411d9e446bSJiri Olsa 12421d9e446bSJiri Olsa if (alias->snapshot) 12431d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1244410136f5SStephane Eranian 1245410136f5SStephane Eranian return 0; 1246410136f5SStephane Eranian } 1247410136f5SStephane Eranian 1248a6146d50SZheng Yan /* 1249a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1250a6146d50SZheng Yan * defined for the alias 1251a6146d50SZheng Yan */ 1252410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 125346441bdcSMatt Fleming struct perf_pmu_info *info) 1254a6146d50SZheng Yan { 12556cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 12565c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1257a6146d50SZheng Yan int ret; 1258a6146d50SZheng Yan 1259044330c1SMatt Fleming info->per_pkg = false; 1260044330c1SMatt Fleming 12618a398897SStephane Eranian /* 12628a398897SStephane Eranian * Mark unit and scale as not set 12638a398897SStephane Eranian * (different from default values, see below) 12648a398897SStephane Eranian */ 126546441bdcSMatt Fleming info->unit = NULL; 126646441bdcSMatt Fleming info->scale = 0.0; 12671d9e446bSJiri Olsa info->snapshot = false; 126837932c18SAndi Kleen info->metric_expr = NULL; 126996284814SAndi Kleen info->metric_name = NULL; 1270410136f5SStephane Eranian 1271a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1272a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1273a6146d50SZheng Yan if (!alias) 1274a6146d50SZheng Yan continue; 1275a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1276a6146d50SZheng Yan if (ret) 1277a6146d50SZheng Yan return ret; 1278410136f5SStephane Eranian 12791d9e446bSJiri Olsa ret = check_info_data(alias, info); 1280410136f5SStephane Eranian if (ret) 1281410136f5SStephane Eranian return ret; 1282410136f5SStephane Eranian 1283044330c1SMatt Fleming if (alias->per_pkg) 1284044330c1SMatt Fleming info->per_pkg = true; 128537932c18SAndi Kleen info->metric_expr = alias->metric_expr; 128696284814SAndi Kleen info->metric_name = alias->metric_name; 1287044330c1SMatt Fleming 1288e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 12891dc92556SIan Rogers parse_events_term__delete(term); 1290a6146d50SZheng Yan } 12918a398897SStephane Eranian 12928a398897SStephane Eranian /* 12938a398897SStephane Eranian * if no unit or scale foundin aliases, then 12948a398897SStephane Eranian * set defaults as for evsel 12958a398897SStephane Eranian * unit cannot left to NULL 12968a398897SStephane Eranian */ 129746441bdcSMatt Fleming if (info->unit == NULL) 129846441bdcSMatt Fleming info->unit = ""; 12998a398897SStephane Eranian 130046441bdcSMatt Fleming if (info->scale == 0.0) 130146441bdcSMatt Fleming info->scale = 1.0; 13028a398897SStephane Eranian 1303a6146d50SZheng Yan return 0; 1304a6146d50SZheng Yan } 1305a6146d50SZheng Yan 1306cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1307cd82a32eSJiri Olsa int config, unsigned long *bits) 1308cd82a32eSJiri Olsa { 13095c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1310cd82a32eSJiri Olsa 1311cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1312cd82a32eSJiri Olsa if (!format) 1313cd82a32eSJiri Olsa return -ENOMEM; 1314cd82a32eSJiri Olsa 1315cd82a32eSJiri Olsa format->name = strdup(name); 1316cd82a32eSJiri Olsa format->value = config; 1317cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1318cd82a32eSJiri Olsa 1319cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1320cd82a32eSJiri Olsa return 0; 1321cd82a32eSJiri Olsa } 1322cd82a32eSJiri Olsa 1323cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1324cd82a32eSJiri Olsa { 1325cd82a32eSJiri Olsa long b; 1326cd82a32eSJiri Olsa 1327cd82a32eSJiri Olsa if (!to) 1328cd82a32eSJiri Olsa to = from; 1329cd82a32eSJiri Olsa 133015268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1331cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1332cd82a32eSJiri Olsa set_bit(b, bits); 1333cd82a32eSJiri Olsa } 1334dc098b35SAndi Kleen 1335aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1336aaea3617SCody P Schafer { 1337aaea3617SCody P Schafer if (b > a) 1338aaea3617SCody P Schafer return 0; 1339aaea3617SCody P Schafer return a - b; 1340aaea3617SCody P Schafer } 1341aaea3617SCody P Schafer 1342dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1343dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1344dc098b35SAndi Kleen { 1345aaea3617SCody P Schafer struct parse_events_term *term; 1346aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1347aaea3617SCody P Schafer 1348aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1349aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1350aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1351aaea3617SCody P Schafer ",%s=%s", term->config, 1352aaea3617SCody P Schafer term->val.str); 1353aaea3617SCody P Schafer } 1354aaea3617SCody P Schafer 1355aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1356aaea3617SCody P Schafer buf[used] = '/'; 1357aaea3617SCody P Schafer used++; 1358aaea3617SCody P Schafer } 1359aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1360aaea3617SCody P Schafer buf[used] = '\0'; 1361aaea3617SCody P Schafer used++; 1362aaea3617SCody P Schafer } else 1363aaea3617SCody P Schafer buf[len - 1] = '\0'; 1364aaea3617SCody P Schafer 1365dc098b35SAndi Kleen return buf; 1366dc098b35SAndi Kleen } 1367dc098b35SAndi Kleen 1368dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1369dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1370dc098b35SAndi Kleen { 1371dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1372dc098b35SAndi Kleen return buf; 1373dc098b35SAndi Kleen } 1374dc098b35SAndi Kleen 1375dd5f1036SAndi Kleen struct sevent { 137608e60ed1SAndi Kleen char *name; 137708e60ed1SAndi Kleen char *desc; 1378dd5f1036SAndi Kleen char *topic; 1379f2361024SAndi Kleen char *str; 1380f2361024SAndi Kleen char *pmu; 13817f372a63SAndi Kleen char *metric_expr; 138296284814SAndi Kleen char *metric_name; 138308e60ed1SAndi Kleen }; 138408e60ed1SAndi Kleen 1385dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1386dc098b35SAndi Kleen { 1387dd5f1036SAndi Kleen const struct sevent *as = a; 1388dd5f1036SAndi Kleen const struct sevent *bs = b; 138908e60ed1SAndi Kleen 139008e60ed1SAndi Kleen /* Put extra events last */ 139108e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 139208e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1393dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1394dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1395dd5f1036SAndi Kleen 1396dd5f1036SAndi Kleen if (n) 1397dd5f1036SAndi Kleen return n; 1398dd5f1036SAndi Kleen } 139908e60ed1SAndi Kleen return strcmp(as->name, bs->name); 140008e60ed1SAndi Kleen } 140108e60ed1SAndi Kleen 140208e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 140308e60ed1SAndi Kleen { 140408e60ed1SAndi Kleen int column = start; 140508e60ed1SAndi Kleen int n; 140608e60ed1SAndi Kleen 140708e60ed1SAndi Kleen while (*s) { 140808e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 140908e60ed1SAndi Kleen 141008e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 141108e60ed1SAndi Kleen printf("\n%*s", start, ""); 141208e60ed1SAndi Kleen column = start + corr; 141308e60ed1SAndi Kleen } 141408e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 141508e60ed1SAndi Kleen if (n <= 0) 141608e60ed1SAndi Kleen break; 141708e60ed1SAndi Kleen s += wlen; 141808e60ed1SAndi Kleen column += n; 141932858480SArnaldo Carvalho de Melo s = skip_spaces(s); 142008e60ed1SAndi Kleen } 1421dc098b35SAndi Kleen } 1422dc098b35SAndi Kleen 1423d504fae9SJohn Garry bool is_pmu_core(const char *name) 1424d504fae9SJohn Garry { 1425d504fae9SJohn Garry return !strcmp(name, "cpu") || is_arm_pmu_core(name); 1426d504fae9SJohn Garry } 1427d504fae9SJohn Garry 1428c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1429a7f6c8c8SJin Yao bool long_desc, bool details_flag, bool deprecated) 1430dc098b35SAndi Kleen { 1431dc098b35SAndi Kleen struct perf_pmu *pmu; 1432dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1433dc098b35SAndi Kleen char buf[1024]; 1434dc098b35SAndi Kleen int printed = 0; 1435dc098b35SAndi Kleen int len, j; 1436dd5f1036SAndi Kleen struct sevent *aliases; 143708e60ed1SAndi Kleen int numdesc = 0; 143861eb2eb4SAndi Kleen int columns = pager_get_columns(); 1439dd5f1036SAndi Kleen char *topic = NULL; 1440dc098b35SAndi Kleen 1441dc098b35SAndi Kleen pmu = NULL; 1442dc098b35SAndi Kleen len = 0; 144342634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1444dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1445dc098b35SAndi Kleen len++; 144642634bc7SAdrian Hunter if (pmu->selectable) 144742634bc7SAdrian Hunter len++; 144842634bc7SAdrian Hunter } 1449dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1450dc098b35SAndi Kleen if (!aliases) 14517e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1452dc098b35SAndi Kleen pmu = NULL; 1453dc098b35SAndi Kleen j = 0; 145442634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1455dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 145608e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 145708e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1458dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1459dc098b35SAndi Kleen 1460a7f6c8c8SJin Yao if (alias->deprecated && !deprecated) 1461a7f6c8c8SJin Yao continue; 1462a7f6c8c8SJin Yao 1463dc098b35SAndi Kleen if (event_glob != NULL && 146438d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 146538d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 146667bdc35fSAndi Kleen event_glob)) || 146767bdc35fSAndi Kleen (alias->topic && 146867bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1469dc098b35SAndi Kleen continue; 14707e4772dcSArnaldo Carvalho de Melo 147108e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 14727e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 14737e4772dcSArnaldo Carvalho de Melo 147408e60ed1SAndi Kleen aliases[j].name = name; 147508e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 147608e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 147708e60ed1SAndi Kleen sizeof(buf), 147808e60ed1SAndi Kleen pmu, alias); 147908e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 148008e60ed1SAndi Kleen if (!aliases[j].name) 14817e4772dcSArnaldo Carvalho de Melo goto out_enomem; 148208e60ed1SAndi Kleen 1483c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1484c8d6828aSSukadev Bhattiprolu alias->desc; 1485dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1486f2361024SAndi Kleen aliases[j].str = alias->str; 1487f2361024SAndi Kleen aliases[j].pmu = pmu->name; 14887f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 148996284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1490dc098b35SAndi Kleen j++; 1491dc098b35SAndi Kleen } 1492fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1493fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 14947e4772dcSArnaldo Carvalho de Melo char *s; 14957e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 14967e4772dcSArnaldo Carvalho de Melo goto out_enomem; 149708e60ed1SAndi Kleen aliases[j].name = s; 149842634bc7SAdrian Hunter j++; 149942634bc7SAdrian Hunter } 150042634bc7SAdrian Hunter } 1501dc098b35SAndi Kleen len = j; 1502dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1503dc098b35SAndi Kleen for (j = 0; j < len; j++) { 150415b22ed3SAndi Kleen /* Skip duplicates */ 150515b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 150615b22ed3SAndi Kleen continue; 1507dc098b35SAndi Kleen if (name_only) { 150808e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1509dc098b35SAndi Kleen continue; 1510dc098b35SAndi Kleen } 15111c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 151208e60ed1SAndi Kleen if (numdesc++ == 0) 151308e60ed1SAndi Kleen printf("\n"); 1514dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1515dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1516dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1517dd5f1036SAndi Kleen aliases[j].topic); 1518dd5f1036SAndi Kleen topic = aliases[j].topic; 1519dd5f1036SAndi Kleen } 152008e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 152108e60ed1SAndi Kleen printf("%*s", 8, "["); 152208e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 152308e60ed1SAndi Kleen printf("]\n"); 1524bf874fcfSAndi Kleen if (details_flag) { 15257f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 152696284814SAndi Kleen if (aliases[j].metric_name) 152796284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 15287f372a63SAndi Kleen if (aliases[j].metric_expr) 15297f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 15307f372a63SAndi Kleen putchar('\n'); 15317f372a63SAndi Kleen } 153208e60ed1SAndi Kleen } else 153308e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1534dc098b35SAndi Kleen printed++; 1535dc098b35SAndi Kleen } 1536dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1537dc098b35SAndi Kleen printf("\n"); 15387e4772dcSArnaldo Carvalho de Melo out_free: 15397e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 154008e60ed1SAndi Kleen zfree(&aliases[j].name); 15417e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 15427e4772dcSArnaldo Carvalho de Melo return; 15437e4772dcSArnaldo Carvalho de Melo 15447e4772dcSArnaldo Carvalho de Melo out_enomem: 15457e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 15467e4772dcSArnaldo Carvalho de Melo if (aliases) 15477e4772dcSArnaldo Carvalho de Melo goto out_free; 1548dc098b35SAndi Kleen } 15494cabc3d1SAndi Kleen 15504cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 15514cabc3d1SAndi Kleen { 15524cabc3d1SAndi Kleen struct perf_pmu *pmu; 15534cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 15544cabc3d1SAndi Kleen 15554cabc3d1SAndi Kleen pmu = NULL; 15564cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 15574cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 15584cabc3d1SAndi Kleen continue; 15594cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 15604cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 15614cabc3d1SAndi Kleen return true; 15624cabc3d1SAndi Kleen } 15634cabc3d1SAndi Kleen return false; 15644cabc3d1SAndi Kleen } 15657d4bdab5SAdrian Hunter 15667d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 15677d4bdab5SAdrian Hunter { 15687d4bdab5SAdrian Hunter char path[PATH_MAX]; 15697d4bdab5SAdrian Hunter const char *sysfs; 15707d4bdab5SAdrian Hunter 15717d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 15727d4bdab5SAdrian Hunter if (!sysfs) 15737d4bdab5SAdrian Hunter return NULL; 15747d4bdab5SAdrian Hunter 15757d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 15767d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 1577d9664582SAndi Kleen if (!file_available(path)) 15787d4bdab5SAdrian Hunter return NULL; 15797d4bdab5SAdrian Hunter return fopen(path, "r"); 15807d4bdab5SAdrian Hunter } 15817d4bdab5SAdrian Hunter 15827d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 15837d4bdab5SAdrian Hunter ...) 15847d4bdab5SAdrian Hunter { 15857d4bdab5SAdrian Hunter va_list args; 15867d4bdab5SAdrian Hunter FILE *file; 15877d4bdab5SAdrian Hunter int ret = EOF; 15887d4bdab5SAdrian Hunter 15897d4bdab5SAdrian Hunter va_start(args, fmt); 15907d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 15917d4bdab5SAdrian Hunter if (file) { 15927d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 15937d4bdab5SAdrian Hunter fclose(file); 15947d4bdab5SAdrian Hunter } 15957d4bdab5SAdrian Hunter va_end(args); 15967d4bdab5SAdrian Hunter return ret; 15977d4bdab5SAdrian Hunter } 15989fbc61f8SKan Liang 15999fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 16009fbc61f8SKan Liang { 16019fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 16029fbc61f8SKan Liang 16039fbc61f8SKan Liang if (!caps) 16049fbc61f8SKan Liang return -ENOMEM; 16059fbc61f8SKan Liang 16069fbc61f8SKan Liang caps->name = strdup(name); 16079fbc61f8SKan Liang if (!caps->name) 16089fbc61f8SKan Liang goto free_caps; 16099fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 16109fbc61f8SKan Liang if (!caps->value) 16119fbc61f8SKan Liang goto free_name; 16129fbc61f8SKan Liang list_add_tail(&caps->list, list); 16139fbc61f8SKan Liang return 0; 16149fbc61f8SKan Liang 16159fbc61f8SKan Liang free_name: 16169fbc61f8SKan Liang zfree(caps->name); 16179fbc61f8SKan Liang free_caps: 16189fbc61f8SKan Liang free(caps); 16199fbc61f8SKan Liang 16209fbc61f8SKan Liang return -ENOMEM; 16219fbc61f8SKan Liang } 16229fbc61f8SKan Liang 16239fbc61f8SKan Liang /* 16249fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 16259fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 16269fbc61f8SKan Liang * Return the number of capabilities 16279fbc61f8SKan Liang */ 16289fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 16299fbc61f8SKan Liang { 16309fbc61f8SKan Liang struct stat st; 16319fbc61f8SKan Liang char caps_path[PATH_MAX]; 16329fbc61f8SKan Liang const char *sysfs = sysfs__mountpoint(); 16339fbc61f8SKan Liang DIR *caps_dir; 16349fbc61f8SKan Liang struct dirent *evt_ent; 16359fbc61f8SKan Liang int nr_caps = 0; 16369fbc61f8SKan Liang 16379fbc61f8SKan Liang if (!sysfs) 16389fbc61f8SKan Liang return -1; 16399fbc61f8SKan Liang 16409fbc61f8SKan Liang snprintf(caps_path, PATH_MAX, 16419fbc61f8SKan Liang "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name); 16429fbc61f8SKan Liang 16439fbc61f8SKan Liang if (stat(caps_path, &st) < 0) 16449fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 16459fbc61f8SKan Liang 16469fbc61f8SKan Liang caps_dir = opendir(caps_path); 16479fbc61f8SKan Liang if (!caps_dir) 16489fbc61f8SKan Liang return -EINVAL; 16499fbc61f8SKan Liang 16509fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 16519fbc61f8SKan Liang char path[PATH_MAX + NAME_MAX + 1]; 16529fbc61f8SKan Liang char *name = evt_ent->d_name; 16539fbc61f8SKan Liang char value[128]; 16549fbc61f8SKan Liang FILE *file; 16559fbc61f8SKan Liang 16569fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 16579fbc61f8SKan Liang continue; 16589fbc61f8SKan Liang 16599fbc61f8SKan Liang snprintf(path, sizeof(path), "%s/%s", caps_path, name); 16609fbc61f8SKan Liang 16619fbc61f8SKan Liang file = fopen(path, "r"); 16629fbc61f8SKan Liang if (!file) 16639fbc61f8SKan Liang continue; 16649fbc61f8SKan Liang 16659fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 16669fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 16679fbc61f8SKan Liang fclose(file); 16689fbc61f8SKan Liang continue; 16699fbc61f8SKan Liang } 16709fbc61f8SKan Liang 16719fbc61f8SKan Liang nr_caps++; 16729fbc61f8SKan Liang fclose(file); 16739fbc61f8SKan Liang } 16749fbc61f8SKan Liang 16759fbc61f8SKan Liang closedir(caps_dir); 16769fbc61f8SKan Liang 16779fbc61f8SKan Liang return nr_caps; 16789fbc61f8SKan Liang } 1679