1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2cd82a32eSJiri Olsa #include <linux/list.h> 3c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 432858480SArnaldo Carvalho de Melo #include <linux/string.h> 57f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 6c47a5599SJin Yao #include <linux/ctype.h> 7fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h> 8cd82a32eSJiri Olsa #include <sys/types.h> 9a43783aeSArnaldo Carvalho de Melo #include <errno.h> 10c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h> 117a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 12cd82a32eSJiri Olsa #include <unistd.h> 13cd82a32eSJiri Olsa #include <stdio.h> 14dc0a6202SAdrian Hunter #include <stdbool.h> 157d4bdab5SAdrian Hunter #include <stdarg.h> 16cd82a32eSJiri Olsa #include <dirent.h> 17cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 18410136f5SStephane Eranian #include <locale.h> 19fbc2844eSWilliam Cohen #include <regex.h> 209c3516d1SJiri Olsa #include <perf/cpumap.h> 21c47a5599SJin Yao #include <fnmatch.h> 225e51b0bbSArnaldo Carvalho de Melo #include "debug.h" 23e12ee9f7SAdrian Hunter #include "evsel.h" 24cd82a32eSJiri Olsa #include "pmu.h" 25cd82a32eSJiri Olsa #include "parse-events.h" 26*e5c6109fSIan Rogers #include "print-events.h" 27933f82ffSSukadev Bhattiprolu #include "header.h" 28a067558eSArnaldo Carvalho de Melo #include "string2.h" 29fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h" 30d9664582SAndi Kleen #include "fncache.h" 3144462430SJin Yao #include "pmu-hybrid.h" 32cd82a32eSJiri Olsa 33e46fc8d9SArnaldo Carvalho de Melo struct perf_pmu perf_pmu__fake; 34e46fc8d9SArnaldo Carvalho de Melo 35fe13d43dSIan Rogers /** 36fe13d43dSIan Rogers * struct perf_pmu_format - Values from a format file read from 37fe13d43dSIan Rogers * <sysfs>/devices/cpu/format/ held in struct perf_pmu. 38fe13d43dSIan Rogers * 39fe13d43dSIan Rogers * For example, the contents of <sysfs>/devices/cpu/format/event may be 40fe13d43dSIan Rogers * "config:0-7" and will be represented here as name="event", 41fe13d43dSIan Rogers * value=PERF_PMU_FORMAT_VALUE_CONFIG and bits 0 to 7 will be set. 42fe13d43dSIan Rogers */ 43ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 44fe13d43dSIan Rogers /** @name: The modifier/file name. */ 45ab1bf653SArnaldo Carvalho de Melo char *name; 46fe13d43dSIan Rogers /** 47fe13d43dSIan Rogers * @value : Which config value the format relates to. Supported values 48fe13d43dSIan Rogers * are from PERF_PMU_FORMAT_VALUE_CONFIG to 49fe13d43dSIan Rogers * PERF_PMU_FORMAT_VALUE_CONFIG_END. 50fe13d43dSIan Rogers */ 51ab1bf653SArnaldo Carvalho de Melo int value; 52fe13d43dSIan Rogers /** @bits: Which config bits are set by this format value. */ 53ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 54fe13d43dSIan Rogers /** @list: Element on list within struct perf_pmu. */ 55ab1bf653SArnaldo Carvalho de Melo struct list_head list; 56ab1bf653SArnaldo Carvalho de Melo }; 57ab1bf653SArnaldo Carvalho de Melo 58cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 59cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 60cd82a32eSJiri Olsa 61cd82a32eSJiri Olsa static LIST_HEAD(pmus); 62c5a26ea4SJin Yao static bool hybrid_scanned; 63cd82a32eSJiri Olsa 64cd82a32eSJiri Olsa /* 65cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 66cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 67cd82a32eSJiri Olsa */ 68cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 69cd82a32eSJiri Olsa { 70cd82a32eSJiri Olsa struct dirent *evt_ent; 71cd82a32eSJiri Olsa DIR *format_dir; 72cd82a32eSJiri Olsa int ret = 0; 73cd82a32eSJiri Olsa 74cd82a32eSJiri Olsa format_dir = opendir(dir); 75cd82a32eSJiri Olsa if (!format_dir) 76cd82a32eSJiri Olsa return -EINVAL; 77cd82a32eSJiri Olsa 78cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 79cd82a32eSJiri Olsa char path[PATH_MAX]; 80cd82a32eSJiri Olsa char *name = evt_ent->d_name; 81cd82a32eSJiri Olsa FILE *file; 82cd82a32eSJiri Olsa 83cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 84cd82a32eSJiri Olsa continue; 85cd82a32eSJiri Olsa 86cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 87cd82a32eSJiri Olsa 88cd82a32eSJiri Olsa ret = -EINVAL; 89cd82a32eSJiri Olsa file = fopen(path, "r"); 90cd82a32eSJiri Olsa if (!file) 91cd82a32eSJiri Olsa break; 92cd82a32eSJiri Olsa 93cd82a32eSJiri Olsa perf_pmu_in = file; 94cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 95cd82a32eSJiri Olsa fclose(file); 96cd82a32eSJiri Olsa } 97cd82a32eSJiri Olsa 98cd82a32eSJiri Olsa closedir(format_dir); 99cd82a32eSJiri Olsa return ret; 100cd82a32eSJiri Olsa } 101cd82a32eSJiri Olsa 102cd82a32eSJiri Olsa /* 103cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 104cd82a32eSJiri Olsa * located at: 105cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 106cd82a32eSJiri Olsa */ 107b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 108cd82a32eSJiri Olsa { 109cd82a32eSJiri Olsa char path[PATH_MAX]; 110cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 111cd82a32eSJiri Olsa 112cd82a32eSJiri Olsa if (!sysfs) 113cd82a32eSJiri Olsa return -1; 114cd82a32eSJiri Olsa 115cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 11650a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 117cd82a32eSJiri Olsa 118d9664582SAndi Kleen if (!file_available(path)) 119d9664582SAndi Kleen return 0; 120cd82a32eSJiri Olsa 121cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 122cd82a32eSJiri Olsa return -1; 123cd82a32eSJiri Olsa 124cd82a32eSJiri Olsa return 0; 125cd82a32eSJiri Olsa } 126cd82a32eSJiri Olsa 127a55ab7c4SJin Yao int perf_pmu__convert_scale(const char *scale, char **end, double *sval) 128d02fc6bcSAndi Kleen { 129d02fc6bcSAndi Kleen char *lc; 130d02fc6bcSAndi Kleen int ret = 0; 131d02fc6bcSAndi Kleen 132d02fc6bcSAndi Kleen /* 133d02fc6bcSAndi Kleen * save current locale 134d02fc6bcSAndi Kleen */ 135d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 136d02fc6bcSAndi Kleen 137d02fc6bcSAndi Kleen /* 138d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 139d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 140d02fc6bcSAndi Kleen * call below. 141d02fc6bcSAndi Kleen */ 142d02fc6bcSAndi Kleen lc = strdup(lc); 143d02fc6bcSAndi Kleen if (!lc) { 144d02fc6bcSAndi Kleen ret = -ENOMEM; 145d02fc6bcSAndi Kleen goto out; 146d02fc6bcSAndi Kleen } 147d02fc6bcSAndi Kleen 148d02fc6bcSAndi Kleen /* 149d02fc6bcSAndi Kleen * force to C locale to ensure kernel 150d02fc6bcSAndi Kleen * scale string is converted correctly. 151d02fc6bcSAndi Kleen * kernel uses default C locale. 152d02fc6bcSAndi Kleen */ 153d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 154d02fc6bcSAndi Kleen 155d02fc6bcSAndi Kleen *sval = strtod(scale, end); 156d02fc6bcSAndi Kleen 157d02fc6bcSAndi Kleen out: 158d02fc6bcSAndi Kleen /* restore locale */ 159d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 160d02fc6bcSAndi Kleen free(lc); 161d02fc6bcSAndi Kleen return ret; 162d02fc6bcSAndi Kleen } 163d02fc6bcSAndi Kleen 164410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 165410136f5SStephane Eranian { 166410136f5SStephane Eranian struct stat st; 167410136f5SStephane Eranian ssize_t sret; 168410136f5SStephane Eranian char scale[128]; 169410136f5SStephane Eranian int fd, ret = -1; 170410136f5SStephane Eranian char path[PATH_MAX]; 171410136f5SStephane Eranian 17211a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 173410136f5SStephane Eranian 174410136f5SStephane Eranian fd = open(path, O_RDONLY); 175410136f5SStephane Eranian if (fd == -1) 176410136f5SStephane Eranian return -1; 177410136f5SStephane Eranian 178410136f5SStephane Eranian if (fstat(fd, &st) < 0) 179410136f5SStephane Eranian goto error; 180410136f5SStephane Eranian 181410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 182410136f5SStephane Eranian if (sret < 0) 183410136f5SStephane Eranian goto error; 184410136f5SStephane Eranian 1859ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1869ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1879ecae065SMadhavan Srinivasan else 188410136f5SStephane Eranian scale[sret] = '\0'; 1899ecae065SMadhavan Srinivasan 190a55ab7c4SJin Yao ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); 191410136f5SStephane Eranian error: 192410136f5SStephane Eranian close(fd); 193410136f5SStephane Eranian return ret; 194410136f5SStephane Eranian } 195410136f5SStephane Eranian 196410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 197410136f5SStephane Eranian { 198410136f5SStephane Eranian char path[PATH_MAX]; 199410136f5SStephane Eranian ssize_t sret; 200410136f5SStephane Eranian int fd; 201410136f5SStephane Eranian 20211a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 203410136f5SStephane Eranian 204410136f5SStephane Eranian fd = open(path, O_RDONLY); 205410136f5SStephane Eranian if (fd == -1) 206410136f5SStephane Eranian return -1; 207410136f5SStephane Eranian 208410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 209410136f5SStephane Eranian if (sret < 0) 210410136f5SStephane Eranian goto error; 211410136f5SStephane Eranian 212410136f5SStephane Eranian close(fd); 213410136f5SStephane Eranian 2149ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 2159ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 2169ecae065SMadhavan Srinivasan else 217410136f5SStephane Eranian alias->unit[sret] = '\0'; 218410136f5SStephane Eranian 219410136f5SStephane Eranian return 0; 220410136f5SStephane Eranian error: 221410136f5SStephane Eranian close(fd); 222410136f5SStephane Eranian alias->unit[0] = '\0'; 223410136f5SStephane Eranian return -1; 224410136f5SStephane Eranian } 225410136f5SStephane Eranian 226044330c1SMatt Fleming static int 227044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 228044330c1SMatt Fleming { 229044330c1SMatt Fleming char path[PATH_MAX]; 230044330c1SMatt Fleming int fd; 231044330c1SMatt Fleming 23211a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 233044330c1SMatt Fleming 234044330c1SMatt Fleming fd = open(path, O_RDONLY); 235044330c1SMatt Fleming if (fd == -1) 236044330c1SMatt Fleming return -1; 237044330c1SMatt Fleming 238044330c1SMatt Fleming close(fd); 239044330c1SMatt Fleming 240044330c1SMatt Fleming alias->per_pkg = true; 241044330c1SMatt Fleming return 0; 242044330c1SMatt Fleming } 243044330c1SMatt Fleming 2441d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2451d9e446bSJiri Olsa char *dir, char *name) 2461d9e446bSJiri Olsa { 2471d9e446bSJiri Olsa char path[PATH_MAX]; 2481d9e446bSJiri Olsa int fd; 2491d9e446bSJiri Olsa 25011a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2511d9e446bSJiri Olsa 2521d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2531d9e446bSJiri Olsa if (fd == -1) 2541d9e446bSJiri Olsa return -1; 2551d9e446bSJiri Olsa 2561d9e446bSJiri Olsa alias->snapshot = true; 2571d9e446bSJiri Olsa close(fd); 2581d9e446bSJiri Olsa return 0; 2591d9e446bSJiri Olsa } 2601d9e446bSJiri Olsa 2616dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2626dde6429SThomas Richter char **new_str) 2636dde6429SThomas Richter { 2646dde6429SThomas Richter if (!*old_str) 2656dde6429SThomas Richter goto set_new; 2666dde6429SThomas Richter 2676dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2686dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2696dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2706dde6429SThomas Richter name, field); 2716dde6429SThomas Richter zfree(old_str); 2726dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2736dde6429SThomas Richter return; 2746dde6429SThomas Richter set_new: 2756dde6429SThomas Richter *old_str = *new_str; 2766dde6429SThomas Richter *new_str = NULL; 2776dde6429SThomas Richter } 2786dde6429SThomas Richter 2796dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2806dde6429SThomas Richter struct perf_pmu_alias *newalias) 2816dde6429SThomas Richter { 2826dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2836dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2846dde6429SThomas Richter &newalias->long_desc); 2856dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2866dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, 2876dde6429SThomas Richter &newalias->metric_expr); 2886dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, 2896dde6429SThomas Richter &newalias->metric_name); 2906dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2916dde6429SThomas Richter old->scale = newalias->scale; 2926dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2936dde6429SThomas Richter old->snapshot = newalias->snapshot; 2946dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2956dde6429SThomas Richter } 2966dde6429SThomas Richter 2976dde6429SThomas Richter /* Delete an alias entry. */ 29822fe5a25SNamhyung Kim void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2996dde6429SThomas Richter { 3006dde6429SThomas Richter zfree(&newalias->name); 3016dde6429SThomas Richter zfree(&newalias->desc); 3026dde6429SThomas Richter zfree(&newalias->long_desc); 3036dde6429SThomas Richter zfree(&newalias->topic); 3046dde6429SThomas Richter zfree(&newalias->str); 3056dde6429SThomas Richter zfree(&newalias->metric_expr); 3066dde6429SThomas Richter zfree(&newalias->metric_name); 30732705de7SJin Yao zfree(&newalias->pmu_name); 3086dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 3096dde6429SThomas Richter free(newalias); 3106dde6429SThomas Richter } 3116dde6429SThomas Richter 3126dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 3136dde6429SThomas Richter * present merge both of them to combine all information. 3146dde6429SThomas Richter */ 3156dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 3166dde6429SThomas Richter struct list_head *alist) 3176dde6429SThomas Richter { 3186dde6429SThomas Richter struct perf_pmu_alias *a; 3196dde6429SThomas Richter 3206dde6429SThomas Richter list_for_each_entry(a, alist, list) { 3216dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 32232705de7SJin Yao if (newalias->pmu_name && a->pmu_name && 32332705de7SJin Yao !strcasecmp(newalias->pmu_name, a->pmu_name)) { 32432705de7SJin Yao continue; 32532705de7SJin Yao } 3266dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 3276dde6429SThomas Richter perf_pmu_free_alias(newalias); 3286dde6429SThomas Richter return true; 3296dde6429SThomas Richter } 3306dde6429SThomas Richter } 3316dde6429SThomas Richter return false; 3326dde6429SThomas Richter } 3336dde6429SThomas Richter 33470c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 33547f572aaSIan Rogers char *desc, char *val, const struct pmu_event *pe) 336a6146d50SZheng Yan { 3370c24d6fbSThomas Richter struct parse_events_term *term; 3385c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 339a6146d50SZheng Yan int ret; 340fedb2b51SAndi Kleen int num; 3410c24d6fbSThomas Richter char newval[256]; 342eab35953SJin Yao char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL, 34332705de7SJin Yao *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL, 34432705de7SJin Yao *pmu_name = NULL; 345eab35953SJin Yao 346eab35953SJin Yao if (pe) { 347eab35953SJin Yao long_desc = (char *)pe->long_desc; 348eab35953SJin Yao topic = (char *)pe->topic; 349eab35953SJin Yao unit = (char *)pe->unit; 350eab35953SJin Yao perpkg = (char *)pe->perpkg; 351eab35953SJin Yao metric_expr = (char *)pe->metric_expr; 352eab35953SJin Yao metric_name = (char *)pe->metric_name; 353eab35953SJin Yao deprecated = (char *)pe->deprecated; 35432705de7SJin Yao pmu_name = (char *)pe->pmu; 355eab35953SJin Yao } 356a6146d50SZheng Yan 357a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 358a6146d50SZheng Yan if (!alias) 359a6146d50SZheng Yan return -ENOMEM; 360a6146d50SZheng Yan 361a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 362410136f5SStephane Eranian alias->scale = 1.0; 363410136f5SStephane Eranian alias->unit[0] = '\0'; 364044330c1SMatt Fleming alias->per_pkg = false; 36584530920SStephane Eranian alias->snapshot = false; 366a7f6c8c8SJin Yao alias->deprecated = false; 367410136f5SStephane Eranian 36870c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 369a6146d50SZheng Yan if (ret) { 37070c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 371a6146d50SZheng Yan free(alias); 372a6146d50SZheng Yan return ret; 373a6146d50SZheng Yan } 374a6146d50SZheng Yan 3750c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3760c24d6fbSThomas Richter * platforms have terms specified as 3770c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3780c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3790c24d6fbSThomas Richter * 3800c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3810c24d6fbSThomas Richter */ 3820c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3830c24d6fbSThomas Richter ret = 0; 3840c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3850c24d6fbSThomas Richter if (ret) 3860c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3870c24d6fbSThomas Richter ","); 3880c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3890c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3900c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3910c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3920c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3930c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3940c24d6fbSThomas Richter } 3950c24d6fbSThomas Richter 396a6146d50SZheng Yan alias->name = strdup(name); 39770c646e0SSukadev Bhattiprolu if (dir) { 398410136f5SStephane Eranian /* 399410136f5SStephane Eranian * load unit name and scale if available 400410136f5SStephane Eranian */ 401410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 402410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 403044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 4041d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 40570c646e0SSukadev Bhattiprolu } 406410136f5SStephane Eranian 40700636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 40896284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 40908e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 410c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 411c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 412dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 413fedb2b51SAndi Kleen if (unit) { 414a55ab7c4SJin Yao if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) 415fedb2b51SAndi Kleen return -1; 416fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 417fedb2b51SAndi Kleen } 418fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 4190c24d6fbSThomas Richter alias->str = strdup(newval); 42032705de7SJin Yao alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL; 421f2361024SAndi Kleen 422a7f6c8c8SJin Yao if (deprecated) 423a7f6c8c8SJin Yao alias->deprecated = true; 424a7f6c8c8SJin Yao 4256dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 426a6146d50SZheng Yan list_add_tail(&alias->list, list); 427410136f5SStephane Eranian 428a6146d50SZheng Yan return 0; 429a6146d50SZheng Yan } 430a6146d50SZheng Yan 43170c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 43270c646e0SSukadev Bhattiprolu { 43370c646e0SSukadev Bhattiprolu char buf[256]; 43470c646e0SSukadev Bhattiprolu int ret; 43570c646e0SSukadev Bhattiprolu 43670c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 43770c646e0SSukadev Bhattiprolu if (ret == 0) 43870c646e0SSukadev Bhattiprolu return -EINVAL; 43970c646e0SSukadev Bhattiprolu 44070c646e0SSukadev Bhattiprolu buf[ret] = 0; 44170c646e0SSukadev Bhattiprolu 442ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 44313c230abSArnaldo Carvalho de Melo strim(buf); 444ea23ac73SThomas Richter 445eab35953SJin Yao return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL); 44670c646e0SSukadev Bhattiprolu } 44770c646e0SSukadev Bhattiprolu 44846441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 44946441bdcSMatt Fleming { 45046441bdcSMatt Fleming size_t len; 45146441bdcSMatt Fleming 45246441bdcSMatt Fleming len = strlen(name); 45346441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 45446441bdcSMatt Fleming return true; 45546441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 45646441bdcSMatt Fleming return true; 457044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 458044330c1SMatt Fleming return true; 4591d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4601d9e446bSJiri Olsa return true; 46146441bdcSMatt Fleming 46246441bdcSMatt Fleming return false; 46346441bdcSMatt Fleming } 46446441bdcSMatt Fleming 465a6146d50SZheng Yan /* 466a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 467a6146d50SZheng Yan * specified in 'dir' parameter. 468a6146d50SZheng Yan */ 469a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 470a6146d50SZheng Yan { 471a6146d50SZheng Yan struct dirent *evt_ent; 472a6146d50SZheng Yan DIR *event_dir; 473a6146d50SZheng Yan 474a6146d50SZheng Yan event_dir = opendir(dir); 475a6146d50SZheng Yan if (!event_dir) 476a6146d50SZheng Yan return -EINVAL; 477a6146d50SZheng Yan 478940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 479a6146d50SZheng Yan char path[PATH_MAX]; 480a6146d50SZheng Yan char *name = evt_ent->d_name; 481a6146d50SZheng Yan FILE *file; 482a6146d50SZheng Yan 483a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 484a6146d50SZheng Yan continue; 485a6146d50SZheng Yan 486410136f5SStephane Eranian /* 48746441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 488410136f5SStephane Eranian */ 48946441bdcSMatt Fleming if (pmu_alias_info_file(name)) 490410136f5SStephane Eranian continue; 491410136f5SStephane Eranian 49277f18153SJiri Olsa scnprintf(path, PATH_MAX, "%s/%s", dir, name); 493a6146d50SZheng Yan 494a6146d50SZheng Yan file = fopen(path, "r"); 495940db6dcSAndi Kleen if (!file) { 496940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 497940db6dcSAndi Kleen continue; 498940db6dcSAndi Kleen } 499410136f5SStephane Eranian 500940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 501940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 502a6146d50SZheng Yan fclose(file); 503a6146d50SZheng Yan } 504a6146d50SZheng Yan 505a6146d50SZheng Yan closedir(event_dir); 506940db6dcSAndi Kleen return 0; 507a6146d50SZheng Yan } 508a6146d50SZheng Yan 509a6146d50SZheng Yan /* 510a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 511a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 512a6146d50SZheng Yan */ 513b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 514a6146d50SZheng Yan { 515a6146d50SZheng Yan char path[PATH_MAX]; 516cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 517a6146d50SZheng Yan 518a6146d50SZheng Yan if (!sysfs) 519a6146d50SZheng Yan return -1; 520a6146d50SZheng Yan 521a6146d50SZheng Yan snprintf(path, PATH_MAX, 522a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 523a6146d50SZheng Yan 524d9664582SAndi Kleen if (!file_available(path)) 525d9664582SAndi Kleen return 0; 526a6146d50SZheng Yan 527a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 528a6146d50SZheng Yan return -1; 529a6146d50SZheng Yan 530a6146d50SZheng Yan return 0; 531a6146d50SZheng Yan } 532a6146d50SZheng Yan 5335c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 534a6146d50SZheng Yan struct list_head *terms) 535a6146d50SZheng Yan { 5367c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 537a6146d50SZheng Yan LIST_HEAD(list); 538a6146d50SZheng Yan int ret; 539a6146d50SZheng Yan 540a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 5417c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 542a6146d50SZheng Yan if (ret) { 543682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 544a6146d50SZheng Yan return ret; 545a6146d50SZheng Yan } 546c2f1ceadSAndi Kleen /* 547c2f1ceadSAndi Kleen * Weak terms don't override command line options, 548c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 549c2f1ceadSAndi Kleen */ 550c2f1ceadSAndi Kleen cloned->weak = true; 5517c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 552a6146d50SZheng Yan } 553a6146d50SZheng Yan list_splice(&list, terms); 554a6146d50SZheng Yan return 0; 555a6146d50SZheng Yan } 556a6146d50SZheng Yan 557cd82a32eSJiri Olsa /* 558cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 559cd82a32eSJiri Olsa * located at: 560cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 561cd82a32eSJiri Olsa */ 562b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 563cd82a32eSJiri Olsa { 564cd82a32eSJiri Olsa char path[PATH_MAX]; 565cd82a32eSJiri Olsa FILE *file; 566cd82a32eSJiri Olsa int ret = 0; 567cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 568cd82a32eSJiri Olsa 569cd82a32eSJiri Olsa if (!sysfs) 570cd82a32eSJiri Olsa return -1; 571cd82a32eSJiri Olsa 572cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 57350a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 574cd82a32eSJiri Olsa 575d9664582SAndi Kleen if (access(path, R_OK) < 0) 576cd82a32eSJiri Olsa return -1; 577cd82a32eSJiri Olsa 578cd82a32eSJiri Olsa file = fopen(path, "r"); 579cd82a32eSJiri Olsa if (!file) 580cd82a32eSJiri Olsa return -EINVAL; 581cd82a32eSJiri Olsa 582cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 583cd82a32eSJiri Olsa ret = -1; 584cd82a32eSJiri Olsa 585cd82a32eSJiri Olsa fclose(file); 586cd82a32eSJiri Olsa return ret; 587cd82a32eSJiri Olsa } 588cd82a32eSJiri Olsa 58950a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 59050a9667cSRobert Richter static void pmu_read_sysfs(void) 59150a9667cSRobert Richter { 59250a9667cSRobert Richter char path[PATH_MAX]; 59350a9667cSRobert Richter DIR *dir; 59450a9667cSRobert Richter struct dirent *dent; 595cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 59650a9667cSRobert Richter 59750a9667cSRobert Richter if (!sysfs) 59850a9667cSRobert Richter return; 59950a9667cSRobert Richter 60050a9667cSRobert Richter snprintf(path, PATH_MAX, 60150a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 60250a9667cSRobert Richter 60350a9667cSRobert Richter dir = opendir(path); 60450a9667cSRobert Richter if (!dir) 60550a9667cSRobert Richter return; 60650a9667cSRobert Richter 60750a9667cSRobert Richter while ((dent = readdir(dir))) { 60850a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 60950a9667cSRobert Richter continue; 61050a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 61150a9667cSRobert Richter perf_pmu__find(dent->d_name); 61250a9667cSRobert Richter } 61350a9667cSRobert Richter 61450a9667cSRobert Richter closedir(dir); 61550a9667cSRobert Richter } 61650a9667cSRobert Richter 617f854839bSJiri Olsa static struct perf_cpu_map *__pmu_cpumask(const char *path) 61866ec1191SMark Rutland { 61966ec1191SMark Rutland FILE *file; 620f854839bSJiri Olsa struct perf_cpu_map *cpus; 62166ec1191SMark Rutland 62266ec1191SMark Rutland file = fopen(path, "r"); 62366ec1191SMark Rutland if (!file) 62466ec1191SMark Rutland return NULL; 62566ec1191SMark Rutland 6269c3516d1SJiri Olsa cpus = perf_cpu_map__read(file); 62766ec1191SMark Rutland fclose(file); 62866ec1191SMark Rutland return cpus; 62966ec1191SMark Rutland } 63066ec1191SMark Rutland 63166ec1191SMark Rutland /* 63266ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 63366ec1191SMark Rutland * may have a "cpus" file. 63466ec1191SMark Rutland */ 63551d54847SJohn Garry #define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier" 63666ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 63766ec1191SMark Rutland 638f854839bSJiri Olsa static struct perf_cpu_map *pmu_cpumask(const char *name) 6397ae92e74SYan, Zheng { 6407ae92e74SYan, Zheng char path[PATH_MAX]; 641f854839bSJiri Olsa struct perf_cpu_map *cpus; 642cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 6437e3fcffeSMark Rutland const char *templates[] = { 64466ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 64566ec1191SMark Rutland CPUS_TEMPLATE_CPU, 6467e3fcffeSMark Rutland NULL 6477e3fcffeSMark Rutland }; 6487e3fcffeSMark Rutland const char **template; 6497ae92e74SYan, Zheng 6507ae92e74SYan, Zheng if (!sysfs) 6517ae92e74SYan, Zheng return NULL; 6527ae92e74SYan, Zheng 6537e3fcffeSMark Rutland for (template = templates; *template; template++) { 6547e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 65566ec1191SMark Rutland cpus = __pmu_cpumask(path); 65666ec1191SMark Rutland if (cpus) 65766ec1191SMark Rutland return cpus; 6587e3fcffeSMark Rutland } 6597ae92e74SYan, Zheng 6607ae92e74SYan, Zheng return NULL; 66166ec1191SMark Rutland } 6627ae92e74SYan, Zheng 66366ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 66466ec1191SMark Rutland { 66566ec1191SMark Rutland char path[PATH_MAX]; 666d9664582SAndi Kleen const char *sysfs; 6677ae92e74SYan, Zheng 66844462430SJin Yao if (perf_pmu__hybrid_mounted(name)) 66944462430SJin Yao return false; 67044462430SJin Yao 671d9664582SAndi Kleen sysfs = sysfs__mountpoint(); 67266ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 673d9664582SAndi Kleen return file_available(path); 6747ae92e74SYan, Zheng } 6757ae92e74SYan, Zheng 67651d54847SJohn Garry static char *pmu_id(const char *name) 67751d54847SJohn Garry { 67851d54847SJohn Garry char path[PATH_MAX], *str; 67951d54847SJohn Garry size_t len; 68051d54847SJohn Garry 68151d54847SJohn Garry snprintf(path, PATH_MAX, SYS_TEMPLATE_ID, name); 68251d54847SJohn Garry 68351d54847SJohn Garry if (sysfs__read_str(path, &str, &len) < 0) 68451d54847SJohn Garry return NULL; 68551d54847SJohn Garry 68651d54847SJohn Garry str[len - 1] = 0; /* remove line feed */ 68751d54847SJohn Garry 68851d54847SJohn Garry return str; 68951d54847SJohn Garry } 69051d54847SJohn Garry 691933f82ffSSukadev Bhattiprolu /* 69214b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 693292c34c1SKan Liang * platforms. 694292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 69514b22ae0SGanapatrao Kulkarni */ 696292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 69714b22ae0SGanapatrao Kulkarni { 69814b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 69914b22ae0SGanapatrao Kulkarni const char *sysfs = sysfs__mountpoint(); 70014b22ae0SGanapatrao Kulkarni 70114b22ae0SGanapatrao Kulkarni if (!sysfs) 70214b22ae0SGanapatrao Kulkarni return 0; 70314b22ae0SGanapatrao Kulkarni 70414b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (specific to arm) */ 70514b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", 70614b22ae0SGanapatrao Kulkarni sysfs, name); 707d9664582SAndi Kleen return file_available(path); 70814b22ae0SGanapatrao Kulkarni } 70914b22ae0SGanapatrao Kulkarni 71029be2fe0SIan Rogers char *perf_pmu__getcpuid(struct perf_pmu *pmu) 711d77ade9fSAndi Kleen { 712d77ade9fSAndi Kleen char *cpuid; 713d77ade9fSAndi Kleen static bool printed; 714d77ade9fSAndi Kleen 715d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 716d77ade9fSAndi Kleen if (cpuid) 717d77ade9fSAndi Kleen cpuid = strdup(cpuid); 718d77ade9fSAndi Kleen if (!cpuid) 71954e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 720d77ade9fSAndi Kleen if (!cpuid) 721d77ade9fSAndi Kleen return NULL; 722d77ade9fSAndi Kleen 723d77ade9fSAndi Kleen if (!printed) { 724d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 725d77ade9fSAndi Kleen printed = true; 726d77ade9fSAndi Kleen } 727d77ade9fSAndi Kleen return cpuid; 728d77ade9fSAndi Kleen } 729d77ade9fSAndi Kleen 7301ba3752aSIan Rogers __weak const struct pmu_events_table *pmu_events_table__find(void) 731e126bef5SJohn Garry { 732eeac7730SIan Rogers return perf_pmu__find_table(NULL); 733e126bef5SJohn Garry } 734e126bef5SJohn Garry 735c07d5c92SJohn Garry /* 736c07d5c92SJohn Garry * Suffix must be in form tok_{digits}, or tok{digits}, or same as pmu_name 737c07d5c92SJohn Garry * to be valid. 738c07d5c92SJohn Garry */ 739c07d5c92SJohn Garry static bool perf_pmu__valid_suffix(const char *pmu_name, char *tok) 740c47a5599SJin Yao { 741c07d5c92SJohn Garry const char *p; 742c47a5599SJin Yao 743c47a5599SJin Yao if (strncmp(pmu_name, tok, strlen(tok))) 744c47a5599SJin Yao return false; 745c47a5599SJin Yao 746c47a5599SJin Yao p = pmu_name + strlen(tok); 747c47a5599SJin Yao if (*p == 0) 748c47a5599SJin Yao return true; 749c47a5599SJin Yao 750c07d5c92SJohn Garry if (*p == '_') 751c47a5599SJin Yao ++p; 752c07d5c92SJohn Garry 753c07d5c92SJohn Garry /* Ensure we end in a number */ 754c07d5c92SJohn Garry while (1) { 755c07d5c92SJohn Garry if (!isdigit(*p)) 756c47a5599SJin Yao return false; 757c07d5c92SJohn Garry if (*(++p) == 0) 758c07d5c92SJohn Garry break; 759c07d5c92SJohn Garry } 760c47a5599SJin Yao 761c47a5599SJin Yao return true; 762c47a5599SJin Yao } 763c47a5599SJin Yao 7645b9a5000SJohn Garry bool pmu_uncore_alias_match(const char *pmu_name, const char *name) 765730670b1SJohn Garry { 766730670b1SJohn Garry char *tmp = NULL, *tok, *str; 767730670b1SJohn Garry bool res; 768730670b1SJohn Garry 769730670b1SJohn Garry str = strdup(pmu_name); 770730670b1SJohn Garry if (!str) 771730670b1SJohn Garry return false; 772730670b1SJohn Garry 773730670b1SJohn Garry /* 774730670b1SJohn Garry * uncore alias may be from different PMU with common prefix 775730670b1SJohn Garry */ 776730670b1SJohn Garry tok = strtok_r(str, ",", &tmp); 777730670b1SJohn Garry if (strncmp(pmu_name, tok, strlen(tok))) { 778730670b1SJohn Garry res = false; 779730670b1SJohn Garry goto out; 780730670b1SJohn Garry } 781730670b1SJohn Garry 782730670b1SJohn Garry /* 783730670b1SJohn Garry * Match more complex aliases where the alias name is a comma-delimited 784730670b1SJohn Garry * list of tokens, orderly contained in the matching PMU name. 785730670b1SJohn Garry * 786730670b1SJohn Garry * Example: For alias "socket,pmuname" and PMU "socketX_pmunameY", we 787730670b1SJohn Garry * match "socket" in "socketX_pmunameY" and then "pmuname" in 788730670b1SJohn Garry * "pmunameY". 789730670b1SJohn Garry */ 790c07d5c92SJohn Garry while (1) { 791c07d5c92SJohn Garry char *next_tok = strtok_r(NULL, ",", &tmp); 792c07d5c92SJohn Garry 793730670b1SJohn Garry name = strstr(name, tok); 794c07d5c92SJohn Garry if (!name || 795c07d5c92SJohn Garry (!next_tok && !perf_pmu__valid_suffix(name, tok))) { 796730670b1SJohn Garry res = false; 797730670b1SJohn Garry goto out; 798730670b1SJohn Garry } 799c07d5c92SJohn Garry if (!next_tok) 800c07d5c92SJohn Garry break; 801c07d5c92SJohn Garry tok = next_tok; 802c07d5c92SJohn Garry name += strlen(tok); 803730670b1SJohn Garry } 804730670b1SJohn Garry 805730670b1SJohn Garry res = true; 806730670b1SJohn Garry out: 807730670b1SJohn Garry free(str); 808730670b1SJohn Garry return res; 809730670b1SJohn Garry } 810730670b1SJohn Garry 811660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data { 812660842e4SIan Rogers struct list_head *head; 813660842e4SIan Rogers const char *name; 814660842e4SIan Rogers const char *cpu_name; 815660842e4SIan Rogers struct perf_pmu *pmu; 816660842e4SIan Rogers }; 817660842e4SIan Rogers 818660842e4SIan Rogers static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe, 8191ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 820660842e4SIan Rogers void *vdata) 821660842e4SIan Rogers { 822660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data *data = vdata; 823660842e4SIan Rogers const char *pname = pe->pmu ? pe->pmu : data->cpu_name; 824660842e4SIan Rogers 825660842e4SIan Rogers if (!pe->name) 826660842e4SIan Rogers return 0; 827660842e4SIan Rogers 828660842e4SIan Rogers if (data->pmu->is_uncore && pmu_uncore_alias_match(pname, data->name)) 829660842e4SIan Rogers goto new_alias; 830660842e4SIan Rogers 831660842e4SIan Rogers if (strcmp(pname, data->name)) 832660842e4SIan Rogers return 0; 833660842e4SIan Rogers 834660842e4SIan Rogers new_alias: 835660842e4SIan Rogers /* need type casts to override 'const' */ 836660842e4SIan Rogers __perf_pmu__new_alias(data->head, NULL, (char *)pe->name, (char *)pe->desc, 837660842e4SIan Rogers (char *)pe->event, pe); 838660842e4SIan Rogers return 0; 839660842e4SIan Rogers } 840660842e4SIan Rogers 841933f82ffSSukadev Bhattiprolu /* 842933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 843933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 844933f82ffSSukadev Bhattiprolu * as aliases. 845933f82ffSSukadev Bhattiprolu */ 846eeac7730SIan Rogers void pmu_add_cpu_aliases_table(struct list_head *head, struct perf_pmu *pmu, 8471ba3752aSIan Rogers const struct pmu_events_table *table) 848933f82ffSSukadev Bhattiprolu { 849660842e4SIan Rogers struct pmu_add_cpu_aliases_map_data data = { 850660842e4SIan Rogers .head = head, 851660842e4SIan Rogers .name = pmu->name, 852660842e4SIan Rogers .cpu_name = is_arm_pmu_core(pmu->name) ? pmu->name : "cpu", 853660842e4SIan Rogers .pmu = pmu, 854660842e4SIan Rogers }; 855fedb2b51SAndi Kleen 856660842e4SIan Rogers pmu_events_table_for_each_event(table, pmu_add_cpu_aliases_map_callback, &data); 857933f82ffSSukadev Bhattiprolu } 858933f82ffSSukadev Bhattiprolu 859e45ad701SJohn Garry static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 860e45ad701SJohn Garry { 8611ba3752aSIan Rogers const struct pmu_events_table *table; 862e45ad701SJohn Garry 863eeac7730SIan Rogers table = perf_pmu__find_table(pmu); 864eeac7730SIan Rogers if (!table) 865e45ad701SJohn Garry return; 866e45ad701SJohn Garry 867eeac7730SIan Rogers pmu_add_cpu_aliases_table(head, pmu, table); 868e45ad701SJohn Garry } 869e45ad701SJohn Garry 8704513c719SJohn Garry struct pmu_sys_event_iter_data { 8714513c719SJohn Garry struct list_head *head; 8724513c719SJohn Garry struct perf_pmu *pmu; 8734513c719SJohn Garry }; 8744513c719SJohn Garry 87529be2fe0SIan Rogers static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe, 8761ba3752aSIan Rogers const struct pmu_events_table *table __maybe_unused, 87729be2fe0SIan Rogers void *data) 8784513c719SJohn Garry { 8794513c719SJohn Garry struct pmu_sys_event_iter_data *idata = data; 8804513c719SJohn Garry struct perf_pmu *pmu = idata->pmu; 8814513c719SJohn Garry 8824513c719SJohn Garry if (!pe->name) { 8834513c719SJohn Garry if (pe->metric_group || pe->metric_name) 8844513c719SJohn Garry return 0; 8854513c719SJohn Garry return -EINVAL; 8864513c719SJohn Garry } 8874513c719SJohn Garry 8884513c719SJohn Garry if (!pe->compat || !pe->pmu) 8894513c719SJohn Garry return 0; 8904513c719SJohn Garry 8914513c719SJohn Garry if (!strcmp(pmu->id, pe->compat) && 8924513c719SJohn Garry pmu_uncore_alias_match(pe->pmu, pmu->name)) { 8934513c719SJohn Garry __perf_pmu__new_alias(idata->head, NULL, 8944513c719SJohn Garry (char *)pe->name, 8954513c719SJohn Garry (char *)pe->desc, 8964513c719SJohn Garry (char *)pe->event, 897eab35953SJin Yao pe); 8984513c719SJohn Garry } 8994513c719SJohn Garry 9004513c719SJohn Garry return 0; 9014513c719SJohn Garry } 9024513c719SJohn Garry 903e199f47fSJohn Garry void pmu_add_sys_aliases(struct list_head *head, struct perf_pmu *pmu) 9044513c719SJohn Garry { 9054513c719SJohn Garry struct pmu_sys_event_iter_data idata = { 9064513c719SJohn Garry .head = head, 9074513c719SJohn Garry .pmu = pmu, 9084513c719SJohn Garry }; 9094513c719SJohn Garry 9104513c719SJohn Garry if (!pmu->id) 9114513c719SJohn Garry return; 9124513c719SJohn Garry 9134513c719SJohn Garry pmu_for_each_sys_event(pmu_add_sys_aliases_iter_fn, &idata); 9144513c719SJohn Garry } 9154513c719SJohn Garry 916c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 917dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 918dc0a6202SAdrian Hunter { 919dc0a6202SAdrian Hunter return NULL; 920dc0a6202SAdrian Hunter } 921dc0a6202SAdrian Hunter 92213d60ba0SKan Liang char * __weak 92313d60ba0SKan Liang pmu_find_real_name(const char *name) 92413d60ba0SKan Liang { 92513d60ba0SKan Liang return (char *)name; 92613d60ba0SKan Liang } 92713d60ba0SKan Liang 92813d60ba0SKan Liang char * __weak 92913d60ba0SKan Liang pmu_find_alias_name(const char *name __maybe_unused) 93013d60ba0SKan Liang { 93113d60ba0SKan Liang return NULL; 93213d60ba0SKan Liang } 93313d60ba0SKan Liang 93490a86bdeSJiri Olsa static int pmu_max_precise(const char *name) 93590a86bdeSJiri Olsa { 93690a86bdeSJiri Olsa char path[PATH_MAX]; 93790a86bdeSJiri Olsa int max_precise = -1; 93890a86bdeSJiri Olsa 93990a86bdeSJiri Olsa scnprintf(path, PATH_MAX, 94090a86bdeSJiri Olsa "bus/event_source/devices/%s/caps/max_precise", 94190a86bdeSJiri Olsa name); 94290a86bdeSJiri Olsa 94390a86bdeSJiri Olsa sysfs__read_int(path, &max_precise); 94490a86bdeSJiri Olsa return max_precise; 94590a86bdeSJiri Olsa } 94690a86bdeSJiri Olsa 94713d60ba0SKan Liang static struct perf_pmu *pmu_lookup(const char *lookup_name) 948cd82a32eSJiri Olsa { 949cd82a32eSJiri Olsa struct perf_pmu *pmu; 950cd82a32eSJiri Olsa LIST_HEAD(format); 951a6146d50SZheng Yan LIST_HEAD(aliases); 952cd82a32eSJiri Olsa __u32 type; 95313d60ba0SKan Liang char *name = pmu_find_real_name(lookup_name); 95449afa7f6SJin Yao bool is_hybrid = perf_pmu__hybrid_mounted(name); 95513d60ba0SKan Liang char *alias_name; 95649afa7f6SJin Yao 95749afa7f6SJin Yao /* 95849afa7f6SJin Yao * Check pmu name for hybrid and the pmu may be invalid in sysfs 95949afa7f6SJin Yao */ 96049afa7f6SJin Yao if (!strncmp(name, "cpu_", 4) && !is_hybrid) 96149afa7f6SJin Yao return NULL; 962cd82a32eSJiri Olsa 963cd82a32eSJiri Olsa /* 964cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 965cd82a32eSJiri Olsa * type value and format definitions. Load both right 966cd82a32eSJiri Olsa * now. 967cd82a32eSJiri Olsa */ 968cd82a32eSJiri Olsa if (pmu_format(name, &format)) 969cd82a32eSJiri Olsa return NULL; 970cd82a32eSJiri Olsa 97115b22ed3SAndi Kleen /* 97215b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 97315b22ed3SAndi Kleen */ 97415b22ed3SAndi Kleen if (pmu_type(name, &type)) 97515b22ed3SAndi Kleen return NULL; 97615b22ed3SAndi Kleen 9773fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 9783fded963SJiri Olsa return NULL; 9793fded963SJiri Olsa 980cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 981cd82a32eSJiri Olsa if (!pmu) 982cd82a32eSJiri Olsa return NULL; 983cd82a32eSJiri Olsa 9847ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 98554e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 98613d60ba0SKan Liang if (!pmu->name) 98713d60ba0SKan Liang goto err; 98813d60ba0SKan Liang 98913d60ba0SKan Liang alias_name = pmu_find_alias_name(name); 99013d60ba0SKan Liang if (alias_name) { 99113d60ba0SKan Liang pmu->alias_name = strdup(alias_name); 99213d60ba0SKan Liang if (!pmu->alias_name) 99313d60ba0SKan Liang goto err; 99413d60ba0SKan Liang } 99513d60ba0SKan Liang 99654e32dc0SGanapatrao Kulkarni pmu->type = type; 99766ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 99851d54847SJohn Garry if (pmu->is_uncore) 99951d54847SJohn Garry pmu->id = pmu_id(name); 100090a86bdeSJiri Olsa pmu->max_precise = pmu_max_precise(name); 100154e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 10024513c719SJohn Garry pmu_add_sys_aliases(&aliases, pmu); 100366ec1191SMark Rutland 1004cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 1005a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 10069fbc61f8SKan Liang INIT_LIST_HEAD(&pmu->caps); 1007cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 1008a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 10099bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 1010dc0a6202SAdrian Hunter 1011e5f4afbeSIan Rogers if (is_hybrid) 101244462430SJin Yao list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus); 101344462430SJin Yao 1014dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 1015dc0a6202SAdrian Hunter 1016cd82a32eSJiri Olsa return pmu; 101713d60ba0SKan Liang err: 101813d60ba0SKan Liang if (pmu->name) 101913d60ba0SKan Liang free(pmu->name); 102013d60ba0SKan Liang free(pmu); 102113d60ba0SKan Liang return NULL; 1022cd82a32eSJiri Olsa } 1023cd82a32eSJiri Olsa 1024e552b7beSRob Herring void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu) 1025e552b7beSRob Herring { 1026e552b7beSRob Herring struct perf_pmu_format *format; 1027e552b7beSRob Herring 1028e552b7beSRob Herring /* fake pmu doesn't have format list */ 1029e552b7beSRob Herring if (pmu == &perf_pmu__fake) 1030e552b7beSRob Herring return; 1031e552b7beSRob Herring 1032e552b7beSRob Herring list_for_each_entry(format, &pmu->format, list) 1033e552b7beSRob Herring if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) { 1034e552b7beSRob Herring pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'" 1035e552b7beSRob Herring "which is not supported by this version of perf!\n", 1036e552b7beSRob Herring pmu->name, format->name, format->value); 1037e552b7beSRob Herring return; 1038e552b7beSRob Herring } 1039e552b7beSRob Herring } 1040e552b7beSRob Herring 1041b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 1042cd82a32eSJiri Olsa { 1043cd82a32eSJiri Olsa struct perf_pmu *pmu; 1044cd82a32eSJiri Olsa 104513d60ba0SKan Liang list_for_each_entry(pmu, &pmus, list) { 104613d60ba0SKan Liang if (!strcmp(pmu->name, name) || 104713d60ba0SKan Liang (pmu->alias_name && !strcmp(pmu->alias_name, name))) 1048cd82a32eSJiri Olsa return pmu; 104913d60ba0SKan Liang } 1050cd82a32eSJiri Olsa 1051cd82a32eSJiri Olsa return NULL; 1052cd82a32eSJiri Olsa } 1053cd82a32eSJiri Olsa 10543a50dc76SStephane Eranian struct perf_pmu *perf_pmu__find_by_type(unsigned int type) 10553a50dc76SStephane Eranian { 10563a50dc76SStephane Eranian struct perf_pmu *pmu; 10573a50dc76SStephane Eranian 10583a50dc76SStephane Eranian list_for_each_entry(pmu, &pmus, list) 10593a50dc76SStephane Eranian if (pmu->type == type) 10603a50dc76SStephane Eranian return pmu; 10613a50dc76SStephane Eranian 10623a50dc76SStephane Eranian return NULL; 10633a50dc76SStephane Eranian } 10643a50dc76SStephane Eranian 106550a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 106650a9667cSRobert Richter { 106750a9667cSRobert Richter /* 106850a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 106950a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 107050a9667cSRobert Richter */ 107150a9667cSRobert Richter if (!pmu) { 107250a9667cSRobert Richter pmu_read_sysfs(); 107350a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 107450a9667cSRobert Richter } 107550a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 107650a9667cSRobert Richter return pmu; 107750a9667cSRobert Richter return NULL; 107850a9667cSRobert Richter } 107950a9667cSRobert Richter 1080e76026bdSArnaldo Carvalho de Melo struct perf_pmu *evsel__find_pmu(struct evsel *evsel) 1081e12ee9f7SAdrian Hunter { 1082e12ee9f7SAdrian Hunter struct perf_pmu *pmu = NULL; 1083e12ee9f7SAdrian Hunter 1084f7400262SNamhyung Kim if (evsel->pmu) 1085f7400262SNamhyung Kim return evsel->pmu; 1086f7400262SNamhyung Kim 1087e12ee9f7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1088e12ee9f7SAdrian Hunter if (pmu->type == evsel->core.attr.type) 1089e12ee9f7SAdrian Hunter break; 1090e12ee9f7SAdrian Hunter } 1091e12ee9f7SAdrian Hunter 1092f7400262SNamhyung Kim evsel->pmu = pmu; 1093e12ee9f7SAdrian Hunter return pmu; 1094e12ee9f7SAdrian Hunter } 1095e12ee9f7SAdrian Hunter 109639453ed5SArnaldo Carvalho de Melo bool evsel__is_aux_event(struct evsel *evsel) 1097e12ee9f7SAdrian Hunter { 1098e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 1099e12ee9f7SAdrian Hunter 1100e12ee9f7SAdrian Hunter return pmu && pmu->auxtrace; 1101e12ee9f7SAdrian Hunter } 1102e12ee9f7SAdrian Hunter 1103b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 1104cd82a32eSJiri Olsa { 1105cd82a32eSJiri Olsa struct perf_pmu *pmu; 1106cd82a32eSJiri Olsa 1107cd82a32eSJiri Olsa /* 1108cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 1109cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 1110cd82a32eSJiri Olsa * the pmu format definitions. 1111cd82a32eSJiri Olsa */ 1112cd82a32eSJiri Olsa pmu = pmu_find(name); 1113cd82a32eSJiri Olsa if (pmu) 1114cd82a32eSJiri Olsa return pmu; 1115cd82a32eSJiri Olsa 1116cd82a32eSJiri Olsa return pmu_lookup(name); 1117cd82a32eSJiri Olsa } 1118cd82a32eSJiri Olsa 11195c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 112009ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 1121cd82a32eSJiri Olsa { 11225c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1123cd82a32eSJiri Olsa 1124cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 1125cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 1126cd82a32eSJiri Olsa return format; 1127cd82a32eSJiri Olsa 1128cd82a32eSJiri Olsa return NULL; 1129cd82a32eSJiri Olsa } 1130cd82a32eSJiri Olsa 113109ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 113209ff6071SAdrian Hunter { 113309ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 113409ff6071SAdrian Hunter __u64 bits = 0; 113509ff6071SAdrian Hunter int fbit; 113609ff6071SAdrian Hunter 113709ff6071SAdrian Hunter if (!format) 113809ff6071SAdrian Hunter return 0; 113909ff6071SAdrian Hunter 114009ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 114109ff6071SAdrian Hunter bits |= 1ULL << fbit; 114209ff6071SAdrian Hunter 114309ff6071SAdrian Hunter return bits; 114409ff6071SAdrian Hunter } 114509ff6071SAdrian Hunter 1146a1ac7de6SAdrian Hunter int perf_pmu__format_type(struct list_head *formats, const char *name) 1147a1ac7de6SAdrian Hunter { 1148a1ac7de6SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 1149a1ac7de6SAdrian Hunter 1150a1ac7de6SAdrian Hunter if (!format) 1151a1ac7de6SAdrian Hunter return -1; 1152a1ac7de6SAdrian Hunter 1153a1ac7de6SAdrian Hunter return format->value; 1154a1ac7de6SAdrian Hunter } 1155a1ac7de6SAdrian Hunter 1156cd82a32eSJiri Olsa /* 1157dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 11584d39c89fSIngo Molnar * and unformatted value (value parameter). 1159cd82a32eSJiri Olsa */ 1160dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 1161dc0a6202SAdrian Hunter bool zero) 1162cd82a32eSJiri Olsa { 1163cd82a32eSJiri Olsa unsigned long fbit, vbit; 1164cd82a32eSJiri Olsa 1165cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 1166cd82a32eSJiri Olsa 1167cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 1168cd82a32eSJiri Olsa continue; 1169cd82a32eSJiri Olsa 1170dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 1171dc0a6202SAdrian Hunter *v |= (1llu << fbit); 1172dc0a6202SAdrian Hunter else if (zero) 1173dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 1174cd82a32eSJiri Olsa } 1175cd82a32eSJiri Olsa } 1176cd82a32eSJiri Olsa 11770efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 11780efe6b67SAdrian Hunter { 11791b9caa10SJiri Olsa int w; 11800efe6b67SAdrian Hunter 11811b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 11821b9caa10SJiri Olsa if (!w) 11831b9caa10SJiri Olsa return 0; 11841b9caa10SJiri Olsa if (w < 64) 11851b9caa10SJiri Olsa return (1ULL << w) - 1; 11861b9caa10SJiri Olsa return -1; 11870efe6b67SAdrian Hunter } 11880efe6b67SAdrian Hunter 1189cd82a32eSJiri Olsa /* 1190688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 1191688d4dfcSCody P Schafer * in the remaining terms. 1192688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 1193688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 1194688d4dfcSCody P Schafer * in a config string) later on in the term list. 1195688d4dfcSCody P Schafer */ 1196688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 1197688d4dfcSCody P Schafer struct list_head *head_terms, 1198688d4dfcSCody P Schafer __u64 *value) 1199688d4dfcSCody P Schafer { 1200688d4dfcSCody P Schafer struct parse_events_term *t; 1201688d4dfcSCody P Schafer 1202688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 12032a3d252dSIan Rogers if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM && 12042a3d252dSIan Rogers t->config && !strcmp(t->config, term->config)) { 1205688d4dfcSCody P Schafer t->used = true; 1206688d4dfcSCody P Schafer *value = t->val.num; 1207688d4dfcSCody P Schafer return 0; 1208688d4dfcSCody P Schafer } 1209688d4dfcSCody P Schafer } 1210688d4dfcSCody P Schafer 1211bb963e16SNamhyung Kim if (verbose > 0) 1212688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 1213688d4dfcSCody P Schafer 1214688d4dfcSCody P Schafer return -1; 1215688d4dfcSCody P Schafer } 1216688d4dfcSCody P Schafer 1217ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 1218e64b020bSJiri Olsa { 1219e64b020bSJiri Olsa struct perf_pmu_format *format; 122011db4e29SMasami Hiramatsu char *str = NULL; 122111db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 1222f1417ceaSXin Gao unsigned int i = 0; 1223e64b020bSJiri Olsa 1224ffeb883eSHe Kuang if (!formats) 1225e64b020bSJiri Olsa return NULL; 1226e64b020bSJiri Olsa 1227e64b020bSJiri Olsa /* sysfs exported terms */ 1228ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 122911db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 123011db4e29SMasami Hiramatsu goto error; 1231e64b020bSJiri Olsa 1232ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 123311db4e29SMasami Hiramatsu error: 1234ffeb883eSHe Kuang strbuf_release(&buf); 1235e64b020bSJiri Olsa 1236e64b020bSJiri Olsa return str; 1237e64b020bSJiri Olsa } 1238e64b020bSJiri Olsa 1239688d4dfcSCody P Schafer /* 1240cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 124188aca8d9SCody P Schafer * user input data - term parameter. 1242cd82a32eSJiri Olsa */ 12434ac22b48SIan Rogers static int pmu_config_term(const char *pmu_name, 12444ac22b48SIan Rogers struct list_head *formats, 1245cd82a32eSJiri Olsa struct perf_event_attr *attr, 1246dc0a6202SAdrian Hunter struct parse_events_term *term, 1247688d4dfcSCody P Schafer struct list_head *head_terms, 1248e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1249cd82a32eSJiri Olsa { 12505c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1251cd82a32eSJiri Olsa __u64 *vp; 12520efe6b67SAdrian Hunter __u64 val, max_val; 1253cd82a32eSJiri Olsa 1254cd82a32eSJiri Olsa /* 1255688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 1256688d4dfcSCody P Schafer * skip it in normal eval. 1257688d4dfcSCody P Schafer */ 1258688d4dfcSCody P Schafer if (term->used) 1259688d4dfcSCody P Schafer return 0; 1260688d4dfcSCody P Schafer 1261688d4dfcSCody P Schafer /* 1262cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 1263cd82a32eSJiri Olsa * to be done for them. 1264cd82a32eSJiri Olsa */ 1265cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 1266cd82a32eSJiri Olsa return 0; 1267cd82a32eSJiri Olsa 1268cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 1269688d4dfcSCody P Schafer if (!format) { 1270ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 12714ac22b48SIan Rogers char *unknown_term; 12724ac22b48SIan Rogers char *help_msg; 1273ffeb883eSHe Kuang 12744ac22b48SIan Rogers if (asprintf(&unknown_term, 12754ac22b48SIan Rogers "unknown term '%s' for pmu '%s'", 12764ac22b48SIan Rogers term->config, pmu_name) < 0) 12774ac22b48SIan Rogers unknown_term = NULL; 12784ac22b48SIan Rogers help_msg = parse_events_formats_error_string(pmu_term); 12794ac22b48SIan Rogers if (err) { 12806c191289SIan Rogers parse_events_error__handle(err, term->err_term, 12814ac22b48SIan Rogers unknown_term, 12824ac22b48SIan Rogers help_msg); 12834ac22b48SIan Rogers } else { 12844ac22b48SIan Rogers pr_debug("%s (%s)\n", unknown_term, help_msg); 12854ac22b48SIan Rogers free(unknown_term); 1286e64b020bSJiri Olsa } 12874ac22b48SIan Rogers free(pmu_term); 1288cd82a32eSJiri Olsa return -EINVAL; 1289688d4dfcSCody P Schafer } 1290cd82a32eSJiri Olsa 1291cd82a32eSJiri Olsa switch (format->value) { 1292cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1293cd82a32eSJiri Olsa vp = &attr->config; 1294cd82a32eSJiri Olsa break; 1295cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1296cd82a32eSJiri Olsa vp = &attr->config1; 1297cd82a32eSJiri Olsa break; 1298cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1299cd82a32eSJiri Olsa vp = &attr->config2; 1300cd82a32eSJiri Olsa break; 1301cd82a32eSJiri Olsa default: 1302cd82a32eSJiri Olsa return -EINVAL; 1303cd82a32eSJiri Olsa } 1304cd82a32eSJiri Olsa 130516fa7e82SJiri Olsa /* 1306688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1307688d4dfcSCody P Schafer * using event parameters. 130816fa7e82SJiri Olsa */ 130999e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 131099e7138eSJiri Olsa if (term->no_value && 131199e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 131299e7138eSJiri Olsa if (err) { 13136c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1314448d732cSIan Rogers strdup("no value assigned for term"), 1315448d732cSIan Rogers NULL); 131699e7138eSJiri Olsa } 131799e7138eSJiri Olsa return -EINVAL; 131899e7138eSJiri Olsa } 131999e7138eSJiri Olsa 1320688d4dfcSCody P Schafer val = term->val.num; 132199e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1322688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1323bb963e16SNamhyung Kim if (verbose > 0) { 1324688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1325688d4dfcSCody P Schafer term->config, term->val.str); 1326e64b020bSJiri Olsa } 1327e64b020bSJiri Olsa if (err) { 13286c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1329448d732cSIan Rogers strdup("expected numeric value"), 1330448d732cSIan Rogers NULL); 1331e64b020bSJiri Olsa } 1332688d4dfcSCody P Schafer return -EINVAL; 1333688d4dfcSCody P Schafer } 1334688d4dfcSCody P Schafer 1335688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1336688d4dfcSCody P Schafer return -EINVAL; 1337688d4dfcSCody P Schafer } else 1338688d4dfcSCody P Schafer return -EINVAL; 1339688d4dfcSCody P Schafer 13400efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 13410efe6b67SAdrian Hunter if (val > max_val) { 13420efe6b67SAdrian Hunter if (err) { 1343448d732cSIan Rogers char *err_str; 1344448d732cSIan Rogers 13456c191289SIan Rogers parse_events_error__handle(err, term->err_val, 1346448d732cSIan Rogers asprintf(&err_str, 13470efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 1348448d732cSIan Rogers (unsigned long long)max_val) < 0 1349448d732cSIan Rogers ? strdup("value too big for format") 1350448d732cSIan Rogers : err_str, 1351448d732cSIan Rogers NULL); 13520efe6b67SAdrian Hunter return -EINVAL; 13530efe6b67SAdrian Hunter } 13540efe6b67SAdrian Hunter /* 13550efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 13560efe6b67SAdrian Hunter * silently truncated. 13570efe6b67SAdrian Hunter */ 13580efe6b67SAdrian Hunter } 13590efe6b67SAdrian Hunter 1360688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1361cd82a32eSJiri Olsa return 0; 1362cd82a32eSJiri Olsa } 1363cd82a32eSJiri Olsa 13644ac22b48SIan Rogers int perf_pmu__config_terms(const char *pmu_name, struct list_head *formats, 1365cff7f956SJiri Olsa struct perf_event_attr *attr, 1366dc0a6202SAdrian Hunter struct list_head *head_terms, 1367e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1368cd82a32eSJiri Olsa { 13696cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1370cd82a32eSJiri Olsa 1371688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 13724ac22b48SIan Rogers if (pmu_config_term(pmu_name, formats, attr, term, head_terms, 1373e64b020bSJiri Olsa zero, err)) 1374cd82a32eSJiri Olsa return -EINVAL; 1375688d4dfcSCody P Schafer } 1376cd82a32eSJiri Olsa 1377cd82a32eSJiri Olsa return 0; 1378cd82a32eSJiri Olsa } 1379cd82a32eSJiri Olsa 1380cd82a32eSJiri Olsa /* 1381cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1382cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1383cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1384cd82a32eSJiri Olsa */ 1385cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1386e64b020bSJiri Olsa struct list_head *head_terms, 1387e64b020bSJiri Olsa struct parse_events_error *err) 1388cd82a32eSJiri Olsa { 1389dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1390dc0a6202SAdrian Hunter 1391cd82a32eSJiri Olsa attr->type = pmu->type; 13924ac22b48SIan Rogers return perf_pmu__config_terms(pmu->name, &pmu->format, attr, 13934ac22b48SIan Rogers head_terms, zero, err); 1394cd82a32eSJiri Olsa } 1395cd82a32eSJiri Olsa 13965c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 13976cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1398a6146d50SZheng Yan { 13995c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1400a6146d50SZheng Yan char *name; 1401a6146d50SZheng Yan 1402a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1403a6146d50SZheng Yan return NULL; 1404a6146d50SZheng Yan 1405a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1406a6146d50SZheng Yan if (term->val.num != 1) 1407a6146d50SZheng Yan return NULL; 1408a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1409a6146d50SZheng Yan return NULL; 1410a6146d50SZheng Yan name = term->config; 1411a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1412a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1413a6146d50SZheng Yan return NULL; 1414a6146d50SZheng Yan name = term->val.str; 1415a6146d50SZheng Yan } else { 1416a6146d50SZheng Yan return NULL; 1417a6146d50SZheng Yan } 1418a6146d50SZheng Yan 1419a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1420a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1421a6146d50SZheng Yan return alias; 1422a6146d50SZheng Yan } 1423a6146d50SZheng Yan return NULL; 1424a6146d50SZheng Yan } 1425a6146d50SZheng Yan 1426410136f5SStephane Eranian 14271d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 14281d9e446bSJiri Olsa struct perf_pmu_info *info) 1429410136f5SStephane Eranian { 1430410136f5SStephane Eranian /* 1431410136f5SStephane Eranian * Only one term in event definition can 14321d9e446bSJiri Olsa * define unit, scale and snapshot, fail 14331d9e446bSJiri Olsa * if there's more than one. 1434410136f5SStephane Eranian */ 1435b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 14361d9e446bSJiri Olsa (info->scale && alias->scale) || 14371d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1438410136f5SStephane Eranian return -EINVAL; 1439410136f5SStephane Eranian 1440b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 14411d9e446bSJiri Olsa info->unit = alias->unit; 1442410136f5SStephane Eranian 1443410136f5SStephane Eranian if (alias->scale) 14441d9e446bSJiri Olsa info->scale = alias->scale; 14451d9e446bSJiri Olsa 14461d9e446bSJiri Olsa if (alias->snapshot) 14471d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1448410136f5SStephane Eranian 1449410136f5SStephane Eranian return 0; 1450410136f5SStephane Eranian } 1451410136f5SStephane Eranian 1452a6146d50SZheng Yan /* 1453a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1454a6146d50SZheng Yan * defined for the alias 1455a6146d50SZheng Yan */ 1456410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 145746441bdcSMatt Fleming struct perf_pmu_info *info) 1458a6146d50SZheng Yan { 14596cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 14605c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1461a6146d50SZheng Yan int ret; 1462a6146d50SZheng Yan 1463044330c1SMatt Fleming info->per_pkg = false; 1464044330c1SMatt Fleming 14658a398897SStephane Eranian /* 14668a398897SStephane Eranian * Mark unit and scale as not set 14678a398897SStephane Eranian * (different from default values, see below) 14688a398897SStephane Eranian */ 146946441bdcSMatt Fleming info->unit = NULL; 147046441bdcSMatt Fleming info->scale = 0.0; 14711d9e446bSJiri Olsa info->snapshot = false; 147237932c18SAndi Kleen info->metric_expr = NULL; 147396284814SAndi Kleen info->metric_name = NULL; 1474410136f5SStephane Eranian 1475a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1476a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1477a6146d50SZheng Yan if (!alias) 1478a6146d50SZheng Yan continue; 1479a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1480a6146d50SZheng Yan if (ret) 1481a6146d50SZheng Yan return ret; 1482410136f5SStephane Eranian 14831d9e446bSJiri Olsa ret = check_info_data(alias, info); 1484410136f5SStephane Eranian if (ret) 1485410136f5SStephane Eranian return ret; 1486410136f5SStephane Eranian 1487044330c1SMatt Fleming if (alias->per_pkg) 1488044330c1SMatt Fleming info->per_pkg = true; 148937932c18SAndi Kleen info->metric_expr = alias->metric_expr; 149096284814SAndi Kleen info->metric_name = alias->metric_name; 1491044330c1SMatt Fleming 1492e56fbc9dSArnaldo Carvalho de Melo list_del_init(&term->list); 14931dc92556SIan Rogers parse_events_term__delete(term); 1494a6146d50SZheng Yan } 14958a398897SStephane Eranian 14968a398897SStephane Eranian /* 14978a398897SStephane Eranian * if no unit or scale found in aliases, then 14988a398897SStephane Eranian * set defaults as for evsel 14998a398897SStephane Eranian * unit cannot left to NULL 15008a398897SStephane Eranian */ 150146441bdcSMatt Fleming if (info->unit == NULL) 150246441bdcSMatt Fleming info->unit = ""; 15038a398897SStephane Eranian 150446441bdcSMatt Fleming if (info->scale == 0.0) 150546441bdcSMatt Fleming info->scale = 1.0; 15068a398897SStephane Eranian 1507a6146d50SZheng Yan return 0; 1508a6146d50SZheng Yan } 1509a6146d50SZheng Yan 1510cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1511cd82a32eSJiri Olsa int config, unsigned long *bits) 1512cd82a32eSJiri Olsa { 15135c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1514cd82a32eSJiri Olsa 1515cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1516cd82a32eSJiri Olsa if (!format) 1517cd82a32eSJiri Olsa return -ENOMEM; 1518cd82a32eSJiri Olsa 1519cd82a32eSJiri Olsa format->name = strdup(name); 1520cd82a32eSJiri Olsa format->value = config; 1521cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1522cd82a32eSJiri Olsa 1523cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1524cd82a32eSJiri Olsa return 0; 1525cd82a32eSJiri Olsa } 1526cd82a32eSJiri Olsa 1527cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1528cd82a32eSJiri Olsa { 1529cd82a32eSJiri Olsa long b; 1530cd82a32eSJiri Olsa 1531cd82a32eSJiri Olsa if (!to) 1532cd82a32eSJiri Olsa to = from; 1533cd82a32eSJiri Olsa 153415268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1535cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1536cd82a32eSJiri Olsa set_bit(b, bits); 1537cd82a32eSJiri Olsa } 1538dc098b35SAndi Kleen 1539d26383dcSNamhyung Kim void perf_pmu__del_formats(struct list_head *formats) 1540d26383dcSNamhyung Kim { 1541d26383dcSNamhyung Kim struct perf_pmu_format *fmt, *tmp; 1542d26383dcSNamhyung Kim 1543d26383dcSNamhyung Kim list_for_each_entry_safe(fmt, tmp, formats, list) { 1544d26383dcSNamhyung Kim list_del(&fmt->list); 1545d26383dcSNamhyung Kim free(fmt->name); 1546d26383dcSNamhyung Kim free(fmt); 1547d26383dcSNamhyung Kim } 1548d26383dcSNamhyung Kim } 1549d26383dcSNamhyung Kim 1550aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1551aaea3617SCody P Schafer { 1552aaea3617SCody P Schafer if (b > a) 1553aaea3617SCody P Schafer return 0; 1554aaea3617SCody P Schafer return a - b; 1555aaea3617SCody P Schafer } 1556aaea3617SCody P Schafer 1557eb2d4514SIan Rogers static char *format_alias(char *buf, int len, const struct perf_pmu *pmu, 1558eb2d4514SIan Rogers const struct perf_pmu_alias *alias) 1559dc098b35SAndi Kleen { 1560aaea3617SCody P Schafer struct parse_events_term *term; 1561aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1562aaea3617SCody P Schafer 1563aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1564aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1565aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1566aaea3617SCody P Schafer ",%s=%s", term->config, 1567aaea3617SCody P Schafer term->val.str); 1568aaea3617SCody P Schafer } 1569aaea3617SCody P Schafer 1570aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1571aaea3617SCody P Schafer buf[used] = '/'; 1572aaea3617SCody P Schafer used++; 1573aaea3617SCody P Schafer } 1574aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1575aaea3617SCody P Schafer buf[used] = '\0'; 1576aaea3617SCody P Schafer used++; 1577aaea3617SCody P Schafer } else 1578aaea3617SCody P Schafer buf[len - 1] = '\0'; 1579aaea3617SCody P Schafer 1580dc098b35SAndi Kleen return buf; 1581dc098b35SAndi Kleen } 1582dc098b35SAndi Kleen 1583eb2d4514SIan Rogers /** Struct for ordering events as output in perf list. */ 1584dd5f1036SAndi Kleen struct sevent { 1585eb2d4514SIan Rogers /** PMU for event. */ 1586eb2d4514SIan Rogers const struct perf_pmu *pmu; 1587eb2d4514SIan Rogers /** 1588eb2d4514SIan Rogers * Optional event for name, desc, etc. If not present then this is a 1589eb2d4514SIan Rogers * selectable PMU and the event name is shown as "//". 1590eb2d4514SIan Rogers */ 1591eb2d4514SIan Rogers const struct perf_pmu_alias *event; 1592eb2d4514SIan Rogers /** Is the PMU for the CPU? */ 1593eb2d4514SIan Rogers bool is_cpu; 159408e60ed1SAndi Kleen }; 159508e60ed1SAndi Kleen 1596dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1597dc098b35SAndi Kleen { 1598dd5f1036SAndi Kleen const struct sevent *as = a; 1599dd5f1036SAndi Kleen const struct sevent *bs = b; 1600eb2d4514SIan Rogers const char *a_pmu_name, *b_pmu_name; 1601eb2d4514SIan Rogers const char *a_name = "//", *a_desc = NULL, *a_topic = ""; 1602eb2d4514SIan Rogers const char *b_name = "//", *b_desc = NULL, *b_topic = ""; 16030e0ae874SJin Yao int ret; 160408e60ed1SAndi Kleen 1605eb2d4514SIan Rogers if (as->event) { 1606eb2d4514SIan Rogers a_name = as->event->name; 1607eb2d4514SIan Rogers a_desc = as->event->desc; 1608eb2d4514SIan Rogers a_topic = as->event->topic ?: ""; 1609dd5f1036SAndi Kleen } 1610eb2d4514SIan Rogers if (bs->event) { 1611eb2d4514SIan Rogers b_name = bs->event->name; 1612eb2d4514SIan Rogers b_desc = bs->event->desc; 1613eb2d4514SIan Rogers b_topic = bs->event->topic ?: ""; 1614eb2d4514SIan Rogers } 1615eb2d4514SIan Rogers /* Put extra events last. */ 1616eb2d4514SIan Rogers if (!!a_desc != !!b_desc) 1617eb2d4514SIan Rogers return !!a_desc - !!b_desc; 1618eb2d4514SIan Rogers 1619eb2d4514SIan Rogers /* Order by topics. */ 1620eb2d4514SIan Rogers ret = strcmp(a_topic, b_topic); 1621eb2d4514SIan Rogers if (ret) 1622eb2d4514SIan Rogers return ret; 1623ce0dc7d2SJohn Garry 1624ce0dc7d2SJohn Garry /* Order CPU core events to be first */ 1625ce0dc7d2SJohn Garry if (as->is_cpu != bs->is_cpu) 1626*e5c6109fSIan Rogers return as->is_cpu ? -1 : 1; 1627ce0dc7d2SJohn Garry 1628eb2d4514SIan Rogers /* Order by PMU name. */ 1629eb2d4514SIan Rogers a_pmu_name = as->pmu->name ?: ""; 1630eb2d4514SIan Rogers b_pmu_name = bs->pmu->name ?: ""; 1631eb2d4514SIan Rogers ret = strcmp(a_pmu_name, b_pmu_name); 1632eb2d4514SIan Rogers if (ret) 16330e0ae874SJin Yao return ret; 1634eb2d4514SIan Rogers 1635eb2d4514SIan Rogers /* Order by event name. */ 1636eb2d4514SIan Rogers return strcmp(a_name, b_name); 163708e60ed1SAndi Kleen } 163808e60ed1SAndi Kleen 1639d504fae9SJohn Garry bool is_pmu_core(const char *name) 1640d504fae9SJohn Garry { 1641d504fae9SJohn Garry return !strcmp(name, "cpu") || is_arm_pmu_core(name); 1642d504fae9SJohn Garry } 1643d504fae9SJohn Garry 1644e0257a01SJohn Garry static bool pmu_alias_is_duplicate(struct sevent *alias_a, 1645e0257a01SJohn Garry struct sevent *alias_b) 1646e0257a01SJohn Garry { 1647eb2d4514SIan Rogers const char *a_pmu_name, *b_pmu_name; 1648eb2d4514SIan Rogers const char *a_name = alias_a->event ? alias_a->event->name : "//"; 1649eb2d4514SIan Rogers const char *b_name = alias_b->event ? alias_b->event->name : "//"; 1650eb2d4514SIan Rogers 1651e0257a01SJohn Garry /* Different names -> never duplicates */ 1652eb2d4514SIan Rogers if (strcmp(a_name, b_name)) 1653e0257a01SJohn Garry return false; 1654e0257a01SJohn Garry 1655eb2d4514SIan Rogers /* Don't remove duplicates for different PMUs */ 1656eb2d4514SIan Rogers a_pmu_name = alias_a->pmu->name ?: ""; 1657eb2d4514SIan Rogers b_pmu_name = alias_b->pmu->name ?: ""; 1658eb2d4514SIan Rogers return strcmp(a_pmu_name, b_pmu_name) == 0; 1659e0257a01SJohn Garry } 1660e0257a01SJohn Garry 1661*e5c6109fSIan Rogers void print_pmu_events(const struct print_callbacks *print_cb, void *print_state) 1662dc098b35SAndi Kleen { 1663dc098b35SAndi Kleen struct perf_pmu *pmu; 1664*e5c6109fSIan Rogers struct perf_pmu_alias *event; 1665dc098b35SAndi Kleen char buf[1024]; 1666dc098b35SAndi Kleen int printed = 0; 1667dc098b35SAndi Kleen int len, j; 1668dd5f1036SAndi Kleen struct sevent *aliases; 1669dc098b35SAndi Kleen 1670dc098b35SAndi Kleen pmu = NULL; 1671dc098b35SAndi Kleen len = 0; 167242634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1673*e5c6109fSIan Rogers list_for_each_entry(event, &pmu->aliases, list) 1674dc098b35SAndi Kleen len++; 167542634bc7SAdrian Hunter if (pmu->selectable) 167642634bc7SAdrian Hunter len++; 167742634bc7SAdrian Hunter } 1678dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1679eb2d4514SIan Rogers if (!aliases) { 1680eb2d4514SIan Rogers pr_err("FATAL: not enough memory to print PMU events\n"); 1681eb2d4514SIan Rogers return; 1682eb2d4514SIan Rogers } 1683dc098b35SAndi Kleen pmu = NULL; 1684dc098b35SAndi Kleen j = 0; 168542634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1686*e5c6109fSIan Rogers bool is_cpu = is_pmu_core(pmu->name) || perf_pmu__is_hybrid(pmu->name); 1687eb2d4514SIan Rogers 1688*e5c6109fSIan Rogers list_for_each_entry(event, &pmu->aliases, list) { 1689*e5c6109fSIan Rogers aliases[j].event = event; 1690eb2d4514SIan Rogers aliases[j].pmu = pmu; 1691ce0dc7d2SJohn Garry aliases[j].is_cpu = is_cpu; 1692dc098b35SAndi Kleen j++; 1693dc098b35SAndi Kleen } 1694*e5c6109fSIan Rogers if (pmu->selectable) { 1695eb2d4514SIan Rogers aliases[j].event = NULL; 1696eb2d4514SIan Rogers aliases[j].pmu = pmu; 1697eb2d4514SIan Rogers aliases[j].is_cpu = is_cpu; 169842634bc7SAdrian Hunter j++; 169942634bc7SAdrian Hunter } 170042634bc7SAdrian Hunter } 1701dc098b35SAndi Kleen len = j; 1702dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1703dc098b35SAndi Kleen for (j = 0; j < len; j++) { 1704*e5c6109fSIan Rogers const char *name, *alias = NULL, *scale_unit = NULL, 1705*e5c6109fSIan Rogers *desc = NULL, *long_desc = NULL, 1706*e5c6109fSIan Rogers *encoding_desc = NULL, *topic = NULL, 1707*e5c6109fSIan Rogers *metric_name = NULL, *metric_expr = NULL; 1708*e5c6109fSIan Rogers bool deprecated = false; 1709*e5c6109fSIan Rogers size_t buf_used; 1710eb2d4514SIan Rogers 171115b22ed3SAndi Kleen /* Skip duplicates */ 1712e0257a01SJohn Garry if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1])) 171315b22ed3SAndi Kleen continue; 17140e0ae874SJin Yao 1715eb2d4514SIan Rogers if (!aliases[j].event) { 1716eb2d4514SIan Rogers /* A selectable event. */ 1717*e5c6109fSIan Rogers buf_used = snprintf(buf, sizeof(buf), "%s//", aliases[j].pmu->name) + 1; 1718eb2d4514SIan Rogers name = buf; 1719eb2d4514SIan Rogers } else { 1720*e5c6109fSIan Rogers if (aliases[j].event->desc) { 1721*e5c6109fSIan Rogers name = aliases[j].event->name; 1722*e5c6109fSIan Rogers buf_used = 0; 1723eb2d4514SIan Rogers } else { 1724eb2d4514SIan Rogers name = format_alias(buf, sizeof(buf), aliases[j].pmu, 1725eb2d4514SIan Rogers aliases[j].event); 1726*e5c6109fSIan Rogers if (aliases[j].is_cpu) { 1727*e5c6109fSIan Rogers alias = name; 1728*e5c6109fSIan Rogers name = aliases[j].event->name; 1729eb2d4514SIan Rogers } 1730*e5c6109fSIan Rogers buf_used = strlen(buf) + 1; 1731eb2d4514SIan Rogers } 1732*e5c6109fSIan Rogers if (strlen(aliases[j].event->unit) || aliases[j].event->scale != 1.0) { 1733*e5c6109fSIan Rogers scale_unit = buf + buf_used; 1734*e5c6109fSIan Rogers buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1735*e5c6109fSIan Rogers "%G%s", aliases[j].event->scale, 1736*e5c6109fSIan Rogers aliases[j].event->unit) + 1; 1737dc098b35SAndi Kleen } 1738*e5c6109fSIan Rogers desc = aliases[j].event->desc; 1739*e5c6109fSIan Rogers long_desc = aliases[j].event->long_desc; 1740eb2d4514SIan Rogers topic = aliases[j].event->topic; 1741*e5c6109fSIan Rogers encoding_desc = buf + buf_used; 1742*e5c6109fSIan Rogers buf_used += snprintf(buf + buf_used, sizeof(buf) - buf_used, 1743*e5c6109fSIan Rogers "%s/%s/", aliases[j].pmu->name, 1744*e5c6109fSIan Rogers aliases[j].event->str) + 1; 1745*e5c6109fSIan Rogers metric_name = aliases[j].event->metric_name; 1746*e5c6109fSIan Rogers metric_expr = aliases[j].event->metric_expr; 1747*e5c6109fSIan Rogers deprecated = aliases[j].event->deprecated; 1748dd5f1036SAndi Kleen } 1749*e5c6109fSIan Rogers print_cb->print_event(print_state, 1750*e5c6109fSIan Rogers aliases[j].pmu->name, 1751*e5c6109fSIan Rogers topic, 1752*e5c6109fSIan Rogers name, 1753*e5c6109fSIan Rogers alias, 1754*e5c6109fSIan Rogers scale_unit, 1755*e5c6109fSIan Rogers deprecated, 1756*e5c6109fSIan Rogers "Kernel PMU event", 1757*e5c6109fSIan Rogers desc, 1758*e5c6109fSIan Rogers long_desc, 1759*e5c6109fSIan Rogers encoding_desc, 1760*e5c6109fSIan Rogers metric_name, 1761*e5c6109fSIan Rogers metric_expr); 1762dc098b35SAndi Kleen } 1763dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1764dc098b35SAndi Kleen printf("\n"); 1765eb2d4514SIan Rogers 17667e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 17677e4772dcSArnaldo Carvalho de Melo return; 1768dc098b35SAndi Kleen } 17694cabc3d1SAndi Kleen 17704cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 17714cabc3d1SAndi Kleen { 17724cabc3d1SAndi Kleen struct perf_pmu *pmu; 17734cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 17744cabc3d1SAndi Kleen 17754cabc3d1SAndi Kleen pmu = NULL; 17764cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 17774cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 17784cabc3d1SAndi Kleen continue; 17794cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 17804cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 17814cabc3d1SAndi Kleen return true; 17824cabc3d1SAndi Kleen } 17834cabc3d1SAndi Kleen return false; 17844cabc3d1SAndi Kleen } 17857d4bdab5SAdrian Hunter 17867d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 17877d4bdab5SAdrian Hunter { 17887d4bdab5SAdrian Hunter char path[PATH_MAX]; 17897d4bdab5SAdrian Hunter const char *sysfs; 17907d4bdab5SAdrian Hunter 17917d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 17927d4bdab5SAdrian Hunter if (!sysfs) 17937d4bdab5SAdrian Hunter return NULL; 17947d4bdab5SAdrian Hunter 17957d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 17967d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 1797d9664582SAndi Kleen if (!file_available(path)) 17987d4bdab5SAdrian Hunter return NULL; 17997d4bdab5SAdrian Hunter return fopen(path, "r"); 18007d4bdab5SAdrian Hunter } 18017d4bdab5SAdrian Hunter 18027d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 18037d4bdab5SAdrian Hunter ...) 18047d4bdab5SAdrian Hunter { 18057d4bdab5SAdrian Hunter va_list args; 18067d4bdab5SAdrian Hunter FILE *file; 18077d4bdab5SAdrian Hunter int ret = EOF; 18087d4bdab5SAdrian Hunter 18097d4bdab5SAdrian Hunter va_start(args, fmt); 18107d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 18117d4bdab5SAdrian Hunter if (file) { 18127d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 18137d4bdab5SAdrian Hunter fclose(file); 18147d4bdab5SAdrian Hunter } 18157d4bdab5SAdrian Hunter va_end(args); 18167d4bdab5SAdrian Hunter return ret; 18177d4bdab5SAdrian Hunter } 18189fbc61f8SKan Liang 18199fbc61f8SKan Liang static int perf_pmu__new_caps(struct list_head *list, char *name, char *value) 18209fbc61f8SKan Liang { 18219fbc61f8SKan Liang struct perf_pmu_caps *caps = zalloc(sizeof(*caps)); 18229fbc61f8SKan Liang 18239fbc61f8SKan Liang if (!caps) 18249fbc61f8SKan Liang return -ENOMEM; 18259fbc61f8SKan Liang 18269fbc61f8SKan Liang caps->name = strdup(name); 18279fbc61f8SKan Liang if (!caps->name) 18289fbc61f8SKan Liang goto free_caps; 18299fbc61f8SKan Liang caps->value = strndup(value, strlen(value) - 1); 18309fbc61f8SKan Liang if (!caps->value) 18319fbc61f8SKan Liang goto free_name; 18329fbc61f8SKan Liang list_add_tail(&caps->list, list); 18339fbc61f8SKan Liang return 0; 18349fbc61f8SKan Liang 18359fbc61f8SKan Liang free_name: 18369fbc61f8SKan Liang zfree(caps->name); 18379fbc61f8SKan Liang free_caps: 18389fbc61f8SKan Liang free(caps); 18399fbc61f8SKan Liang 18409fbc61f8SKan Liang return -ENOMEM; 18419fbc61f8SKan Liang } 18429fbc61f8SKan Liang 18439fbc61f8SKan Liang /* 18449fbc61f8SKan Liang * Reading/parsing the given pmu capabilities, which should be located at: 18459fbc61f8SKan Liang * /sys/bus/event_source/devices/<dev>/caps as sysfs group attributes. 18469fbc61f8SKan Liang * Return the number of capabilities 18479fbc61f8SKan Liang */ 18489fbc61f8SKan Liang int perf_pmu__caps_parse(struct perf_pmu *pmu) 18499fbc61f8SKan Liang { 18509fbc61f8SKan Liang struct stat st; 18519fbc61f8SKan Liang char caps_path[PATH_MAX]; 18529fbc61f8SKan Liang const char *sysfs = sysfs__mountpoint(); 18539fbc61f8SKan Liang DIR *caps_dir; 18549fbc61f8SKan Liang struct dirent *evt_ent; 18553339ec44SRavi Bangoria 18563339ec44SRavi Bangoria if (pmu->caps_initialized) 18573339ec44SRavi Bangoria return pmu->nr_caps; 18583339ec44SRavi Bangoria 18593339ec44SRavi Bangoria pmu->nr_caps = 0; 18609fbc61f8SKan Liang 18619fbc61f8SKan Liang if (!sysfs) 18629fbc61f8SKan Liang return -1; 18639fbc61f8SKan Liang 18649fbc61f8SKan Liang snprintf(caps_path, PATH_MAX, 18659fbc61f8SKan Liang "%s" EVENT_SOURCE_DEVICE_PATH "%s/caps", sysfs, pmu->name); 18669fbc61f8SKan Liang 18673339ec44SRavi Bangoria if (stat(caps_path, &st) < 0) { 18683339ec44SRavi Bangoria pmu->caps_initialized = true; 18699fbc61f8SKan Liang return 0; /* no error if caps does not exist */ 18703339ec44SRavi Bangoria } 18719fbc61f8SKan Liang 18729fbc61f8SKan Liang caps_dir = opendir(caps_path); 18739fbc61f8SKan Liang if (!caps_dir) 18749fbc61f8SKan Liang return -EINVAL; 18759fbc61f8SKan Liang 18769fbc61f8SKan Liang while ((evt_ent = readdir(caps_dir)) != NULL) { 18779fbc61f8SKan Liang char path[PATH_MAX + NAME_MAX + 1]; 18789fbc61f8SKan Liang char *name = evt_ent->d_name; 18799fbc61f8SKan Liang char value[128]; 18809fbc61f8SKan Liang FILE *file; 18819fbc61f8SKan Liang 18829fbc61f8SKan Liang if (!strcmp(name, ".") || !strcmp(name, "..")) 18839fbc61f8SKan Liang continue; 18849fbc61f8SKan Liang 18859fbc61f8SKan Liang snprintf(path, sizeof(path), "%s/%s", caps_path, name); 18869fbc61f8SKan Liang 18879fbc61f8SKan Liang file = fopen(path, "r"); 18889fbc61f8SKan Liang if (!file) 18899fbc61f8SKan Liang continue; 18909fbc61f8SKan Liang 18919fbc61f8SKan Liang if (!fgets(value, sizeof(value), file) || 18929fbc61f8SKan Liang (perf_pmu__new_caps(&pmu->caps, name, value) < 0)) { 18939fbc61f8SKan Liang fclose(file); 18949fbc61f8SKan Liang continue; 18959fbc61f8SKan Liang } 18969fbc61f8SKan Liang 18973339ec44SRavi Bangoria pmu->nr_caps++; 18989fbc61f8SKan Liang fclose(file); 18999fbc61f8SKan Liang } 19009fbc61f8SKan Liang 19019fbc61f8SKan Liang closedir(caps_dir); 19029fbc61f8SKan Liang 19033339ec44SRavi Bangoria pmu->caps_initialized = true; 19043339ec44SRavi Bangoria return pmu->nr_caps; 19059fbc61f8SKan Liang } 1906e4064776SJin Yao 1907e4064776SJin Yao void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config, 19088e8bbfb3SIan Rogers const char *name) 1909e4064776SJin Yao { 1910e4064776SJin Yao struct perf_pmu_format *format; 1911e4064776SJin Yao __u64 masks = 0, bits; 1912e4064776SJin Yao char buf[100]; 1913e4064776SJin Yao unsigned int i; 1914e4064776SJin Yao 1915e4064776SJin Yao list_for_each_entry(format, &pmu->format, list) { 1916e4064776SJin Yao if (format->value != PERF_PMU_FORMAT_VALUE_CONFIG) 1917e4064776SJin Yao continue; 1918e4064776SJin Yao 1919e4064776SJin Yao for_each_set_bit(i, format->bits, PERF_PMU_FORMAT_BITS) 1920e4064776SJin Yao masks |= 1ULL << i; 1921e4064776SJin Yao } 1922e4064776SJin Yao 1923e4064776SJin Yao /* 1924e4064776SJin Yao * Kernel doesn't export any valid format bits. 1925e4064776SJin Yao */ 1926e4064776SJin Yao if (masks == 0) 1927e4064776SJin Yao return; 1928e4064776SJin Yao 1929e4064776SJin Yao bits = config & ~masks; 1930e4064776SJin Yao if (bits == 0) 1931e4064776SJin Yao return; 1932e4064776SJin Yao 1933e4064776SJin Yao bitmap_scnprintf((unsigned long *)&bits, sizeof(bits) * 8, buf, sizeof(buf)); 1934e4064776SJin Yao 1935e4064776SJin Yao pr_warning("WARNING: event '%s' not valid (bits %s of config " 1936e4064776SJin Yao "'%llx' not supported by kernel)!\n", 1937e4064776SJin Yao name ?: "N/A", buf, config); 1938e4064776SJin Yao } 1939c5a26ea4SJin Yao 1940c5a26ea4SJin Yao bool perf_pmu__has_hybrid(void) 1941c5a26ea4SJin Yao { 1942c5a26ea4SJin Yao if (!hybrid_scanned) { 1943c5a26ea4SJin Yao hybrid_scanned = true; 1944c5a26ea4SJin Yao perf_pmu__scan(NULL); 1945c5a26ea4SJin Yao } 1946c5a26ea4SJin Yao 1947c5a26ea4SJin Yao return !list_empty(&perf_pmu__hybrid_pmus); 1948c5a26ea4SJin Yao } 1949c47a5599SJin Yao 1950c47a5599SJin Yao int perf_pmu__match(char *pattern, char *name, char *tok) 1951c47a5599SJin Yao { 195213d60ba0SKan Liang if (!name) 195313d60ba0SKan Liang return -1; 195413d60ba0SKan Liang 1955c47a5599SJin Yao if (fnmatch(pattern, name, 0)) 1956c47a5599SJin Yao return -1; 1957c47a5599SJin Yao 1958c47a5599SJin Yao if (tok && !perf_pmu__valid_suffix(name, tok)) 1959c47a5599SJin Yao return -1; 1960c47a5599SJin Yao 1961c47a5599SJin Yao return 0; 1962c47a5599SJin Yao } 19631d3351e6SJin Yao 19641d3351e6SJin Yao int perf_pmu__cpus_match(struct perf_pmu *pmu, struct perf_cpu_map *cpus, 19651d3351e6SJin Yao struct perf_cpu_map **mcpus_ptr, 19661d3351e6SJin Yao struct perf_cpu_map **ucpus_ptr) 19671d3351e6SJin Yao { 19681d3351e6SJin Yao struct perf_cpu_map *pmu_cpus = pmu->cpus; 19691d3351e6SJin Yao struct perf_cpu_map *matched_cpus, *unmatched_cpus; 19706a12a63eSIan Rogers struct perf_cpu cpu; 19716a12a63eSIan Rogers int i, matched_nr = 0, unmatched_nr = 0; 19721d3351e6SJin Yao 19731d3351e6SJin Yao matched_cpus = perf_cpu_map__default_new(); 19741d3351e6SJin Yao if (!matched_cpus) 19751d3351e6SJin Yao return -1; 19761d3351e6SJin Yao 19771d3351e6SJin Yao unmatched_cpus = perf_cpu_map__default_new(); 19781d3351e6SJin Yao if (!unmatched_cpus) { 19791d3351e6SJin Yao perf_cpu_map__put(matched_cpus); 19801d3351e6SJin Yao return -1; 19811d3351e6SJin Yao } 19821d3351e6SJin Yao 19836a12a63eSIan Rogers perf_cpu_map__for_each_cpu(cpu, i, cpus) { 19846a12a63eSIan Rogers if (!perf_cpu_map__has(pmu_cpus, cpu)) 19856a12a63eSIan Rogers unmatched_cpus->map[unmatched_nr++] = cpu; 19861d3351e6SJin Yao else 19876a12a63eSIan Rogers matched_cpus->map[matched_nr++] = cpu; 19881d3351e6SJin Yao } 19891d3351e6SJin Yao 19901d3351e6SJin Yao unmatched_cpus->nr = unmatched_nr; 19911d3351e6SJin Yao matched_cpus->nr = matched_nr; 19921d3351e6SJin Yao *mcpus_ptr = matched_cpus; 19931d3351e6SJin Yao *ucpus_ptr = unmatched_cpus; 19941d3351e6SJin Yao return 0; 19951d3351e6SJin Yao } 1996