1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2cd82a32eSJiri Olsa #include <linux/list.h> 3c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 4cd82a32eSJiri Olsa #include <sys/types.h> 5a43783aeSArnaldo Carvalho de Melo #include <errno.h> 6c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h> 77a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 8cd82a32eSJiri Olsa #include <unistd.h> 9cd82a32eSJiri Olsa #include <stdio.h> 10dc0a6202SAdrian Hunter #include <stdbool.h> 117d4bdab5SAdrian Hunter #include <stdarg.h> 12cd82a32eSJiri Olsa #include <dirent.h> 13cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 14410136f5SStephane Eranian #include <locale.h> 15fbc2844eSWilliam Cohen #include <regex.h> 16cd82a32eSJiri Olsa #include "util.h" 17cd82a32eSJiri Olsa #include "pmu.h" 18cd82a32eSJiri Olsa #include "parse-events.h" 197ae92e74SYan, Zheng #include "cpumap.h" 20933f82ffSSukadev Bhattiprolu #include "header.h" 21933f82ffSSukadev Bhattiprolu #include "pmu-events/pmu-events.h" 2261eb2eb4SAndi Kleen #include "cache.h" 23a067558eSArnaldo Carvalho de Melo #include "string2.h" 24cd82a32eSJiri Olsa 25ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 26ab1bf653SArnaldo Carvalho de Melo char *name; 27ab1bf653SArnaldo Carvalho de Melo int value; 28ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 29ab1bf653SArnaldo Carvalho de Melo struct list_head list; 30ab1bf653SArnaldo Carvalho de Melo }; 31ab1bf653SArnaldo Carvalho de Melo 32cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 33cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 34cd82a32eSJiri Olsa 35cd82a32eSJiri Olsa static LIST_HEAD(pmus); 36cd82a32eSJiri Olsa 37cd82a32eSJiri Olsa /* 38cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 39cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 40cd82a32eSJiri Olsa */ 41cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 42cd82a32eSJiri Olsa { 43cd82a32eSJiri Olsa struct dirent *evt_ent; 44cd82a32eSJiri Olsa DIR *format_dir; 45cd82a32eSJiri Olsa int ret = 0; 46cd82a32eSJiri Olsa 47cd82a32eSJiri Olsa format_dir = opendir(dir); 48cd82a32eSJiri Olsa if (!format_dir) 49cd82a32eSJiri Olsa return -EINVAL; 50cd82a32eSJiri Olsa 51cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 52cd82a32eSJiri Olsa char path[PATH_MAX]; 53cd82a32eSJiri Olsa char *name = evt_ent->d_name; 54cd82a32eSJiri Olsa FILE *file; 55cd82a32eSJiri Olsa 56cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 57cd82a32eSJiri Olsa continue; 58cd82a32eSJiri Olsa 59cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 60cd82a32eSJiri Olsa 61cd82a32eSJiri Olsa ret = -EINVAL; 62cd82a32eSJiri Olsa file = fopen(path, "r"); 63cd82a32eSJiri Olsa if (!file) 64cd82a32eSJiri Olsa break; 65cd82a32eSJiri Olsa 66cd82a32eSJiri Olsa perf_pmu_in = file; 67cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 68cd82a32eSJiri Olsa fclose(file); 69cd82a32eSJiri Olsa } 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa closedir(format_dir); 72cd82a32eSJiri Olsa return ret; 73cd82a32eSJiri Olsa } 74cd82a32eSJiri Olsa 75cd82a32eSJiri Olsa /* 76cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 77cd82a32eSJiri Olsa * located at: 78cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 79cd82a32eSJiri Olsa */ 80b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 81cd82a32eSJiri Olsa { 82cd82a32eSJiri Olsa struct stat st; 83cd82a32eSJiri Olsa char path[PATH_MAX]; 84cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 85cd82a32eSJiri Olsa 86cd82a32eSJiri Olsa if (!sysfs) 87cd82a32eSJiri Olsa return -1; 88cd82a32eSJiri Olsa 89cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 91cd82a32eSJiri Olsa 92cd82a32eSJiri Olsa if (stat(path, &st) < 0) 939bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 94cd82a32eSJiri Olsa 95cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 96cd82a32eSJiri Olsa return -1; 97cd82a32eSJiri Olsa 98cd82a32eSJiri Olsa return 0; 99cd82a32eSJiri Olsa } 100cd82a32eSJiri Olsa 101d02fc6bcSAndi Kleen static int convert_scale(const char *scale, char **end, double *sval) 102d02fc6bcSAndi Kleen { 103d02fc6bcSAndi Kleen char *lc; 104d02fc6bcSAndi Kleen int ret = 0; 105d02fc6bcSAndi Kleen 106d02fc6bcSAndi Kleen /* 107d02fc6bcSAndi Kleen * save current locale 108d02fc6bcSAndi Kleen */ 109d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 110d02fc6bcSAndi Kleen 111d02fc6bcSAndi Kleen /* 112d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 113d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 114d02fc6bcSAndi Kleen * call below. 115d02fc6bcSAndi Kleen */ 116d02fc6bcSAndi Kleen lc = strdup(lc); 117d02fc6bcSAndi Kleen if (!lc) { 118d02fc6bcSAndi Kleen ret = -ENOMEM; 119d02fc6bcSAndi Kleen goto out; 120d02fc6bcSAndi Kleen } 121d02fc6bcSAndi Kleen 122d02fc6bcSAndi Kleen /* 123d02fc6bcSAndi Kleen * force to C locale to ensure kernel 124d02fc6bcSAndi Kleen * scale string is converted correctly. 125d02fc6bcSAndi Kleen * kernel uses default C locale. 126d02fc6bcSAndi Kleen */ 127d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 128d02fc6bcSAndi Kleen 129d02fc6bcSAndi Kleen *sval = strtod(scale, end); 130d02fc6bcSAndi Kleen 131d02fc6bcSAndi Kleen out: 132d02fc6bcSAndi Kleen /* restore locale */ 133d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 134d02fc6bcSAndi Kleen free(lc); 135d02fc6bcSAndi Kleen return ret; 136d02fc6bcSAndi Kleen } 137d02fc6bcSAndi Kleen 138410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 139410136f5SStephane Eranian { 140410136f5SStephane Eranian struct stat st; 141410136f5SStephane Eranian ssize_t sret; 142410136f5SStephane Eranian char scale[128]; 143410136f5SStephane Eranian int fd, ret = -1; 144410136f5SStephane Eranian char path[PATH_MAX]; 145410136f5SStephane Eranian 14611a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 147410136f5SStephane Eranian 148410136f5SStephane Eranian fd = open(path, O_RDONLY); 149410136f5SStephane Eranian if (fd == -1) 150410136f5SStephane Eranian return -1; 151410136f5SStephane Eranian 152410136f5SStephane Eranian if (fstat(fd, &st) < 0) 153410136f5SStephane Eranian goto error; 154410136f5SStephane Eranian 155410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 156410136f5SStephane Eranian if (sret < 0) 157410136f5SStephane Eranian goto error; 158410136f5SStephane Eranian 1599ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1609ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1619ecae065SMadhavan Srinivasan else 162410136f5SStephane Eranian scale[sret] = '\0'; 1639ecae065SMadhavan Srinivasan 164d02fc6bcSAndi Kleen ret = convert_scale(scale, NULL, &alias->scale); 165410136f5SStephane Eranian error: 166410136f5SStephane Eranian close(fd); 167410136f5SStephane Eranian return ret; 168410136f5SStephane Eranian } 169410136f5SStephane Eranian 170410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 171410136f5SStephane Eranian { 172410136f5SStephane Eranian char path[PATH_MAX]; 173410136f5SStephane Eranian ssize_t sret; 174410136f5SStephane Eranian int fd; 175410136f5SStephane Eranian 17611a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 177410136f5SStephane Eranian 178410136f5SStephane Eranian fd = open(path, O_RDONLY); 179410136f5SStephane Eranian if (fd == -1) 180410136f5SStephane Eranian return -1; 181410136f5SStephane Eranian 182410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 183410136f5SStephane Eranian if (sret < 0) 184410136f5SStephane Eranian goto error; 185410136f5SStephane Eranian 186410136f5SStephane Eranian close(fd); 187410136f5SStephane Eranian 1889ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1899ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1909ecae065SMadhavan Srinivasan else 191410136f5SStephane Eranian alias->unit[sret] = '\0'; 192410136f5SStephane Eranian 193410136f5SStephane Eranian return 0; 194410136f5SStephane Eranian error: 195410136f5SStephane Eranian close(fd); 196410136f5SStephane Eranian alias->unit[0] = '\0'; 197410136f5SStephane Eranian return -1; 198410136f5SStephane Eranian } 199410136f5SStephane Eranian 200044330c1SMatt Fleming static int 201044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 202044330c1SMatt Fleming { 203044330c1SMatt Fleming char path[PATH_MAX]; 204044330c1SMatt Fleming int fd; 205044330c1SMatt Fleming 20611a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 207044330c1SMatt Fleming 208044330c1SMatt Fleming fd = open(path, O_RDONLY); 209044330c1SMatt Fleming if (fd == -1) 210044330c1SMatt Fleming return -1; 211044330c1SMatt Fleming 212044330c1SMatt Fleming close(fd); 213044330c1SMatt Fleming 214044330c1SMatt Fleming alias->per_pkg = true; 215044330c1SMatt Fleming return 0; 216044330c1SMatt Fleming } 217044330c1SMatt Fleming 2181d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2191d9e446bSJiri Olsa char *dir, char *name) 2201d9e446bSJiri Olsa { 2211d9e446bSJiri Olsa char path[PATH_MAX]; 2221d9e446bSJiri Olsa int fd; 2231d9e446bSJiri Olsa 22411a64a05SBen Hutchings scnprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2251d9e446bSJiri Olsa 2261d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2271d9e446bSJiri Olsa if (fd == -1) 2281d9e446bSJiri Olsa return -1; 2291d9e446bSJiri Olsa 2301d9e446bSJiri Olsa alias->snapshot = true; 2311d9e446bSJiri Olsa close(fd); 2321d9e446bSJiri Olsa return 0; 2331d9e446bSJiri Olsa } 2341d9e446bSJiri Olsa 2356dde6429SThomas Richter static void perf_pmu_assign_str(char *name, const char *field, char **old_str, 2366dde6429SThomas Richter char **new_str) 2376dde6429SThomas Richter { 2386dde6429SThomas Richter if (!*old_str) 2396dde6429SThomas Richter goto set_new; 2406dde6429SThomas Richter 2416dde6429SThomas Richter if (*new_str) { /* Have new string, check with old */ 2426dde6429SThomas Richter if (strcasecmp(*old_str, *new_str)) 2436dde6429SThomas Richter pr_debug("alias %s differs in field '%s'\n", 2446dde6429SThomas Richter name, field); 2456dde6429SThomas Richter zfree(old_str); 2466dde6429SThomas Richter } else /* Nothing new --> keep old string */ 2476dde6429SThomas Richter return; 2486dde6429SThomas Richter set_new: 2496dde6429SThomas Richter *old_str = *new_str; 2506dde6429SThomas Richter *new_str = NULL; 2516dde6429SThomas Richter } 2526dde6429SThomas Richter 2536dde6429SThomas Richter static void perf_pmu_update_alias(struct perf_pmu_alias *old, 2546dde6429SThomas Richter struct perf_pmu_alias *newalias) 2556dde6429SThomas Richter { 2566dde6429SThomas Richter perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); 2576dde6429SThomas Richter perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, 2586dde6429SThomas Richter &newalias->long_desc); 2596dde6429SThomas Richter perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); 2606dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, 2616dde6429SThomas Richter &newalias->metric_expr); 2626dde6429SThomas Richter perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, 2636dde6429SThomas Richter &newalias->metric_name); 2646dde6429SThomas Richter perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); 2656dde6429SThomas Richter old->scale = newalias->scale; 2666dde6429SThomas Richter old->per_pkg = newalias->per_pkg; 2676dde6429SThomas Richter old->snapshot = newalias->snapshot; 2686dde6429SThomas Richter memcpy(old->unit, newalias->unit, sizeof(old->unit)); 2696dde6429SThomas Richter } 2706dde6429SThomas Richter 2716dde6429SThomas Richter /* Delete an alias entry. */ 2726dde6429SThomas Richter static void perf_pmu_free_alias(struct perf_pmu_alias *newalias) 2736dde6429SThomas Richter { 2746dde6429SThomas Richter zfree(&newalias->name); 2756dde6429SThomas Richter zfree(&newalias->desc); 2766dde6429SThomas Richter zfree(&newalias->long_desc); 2776dde6429SThomas Richter zfree(&newalias->topic); 2786dde6429SThomas Richter zfree(&newalias->str); 2796dde6429SThomas Richter zfree(&newalias->metric_expr); 2806dde6429SThomas Richter zfree(&newalias->metric_name); 2816dde6429SThomas Richter parse_events_terms__purge(&newalias->terms); 2826dde6429SThomas Richter free(newalias); 2836dde6429SThomas Richter } 2846dde6429SThomas Richter 2856dde6429SThomas Richter /* Merge an alias, search in alias list. If this name is already 2866dde6429SThomas Richter * present merge both of them to combine all information. 2876dde6429SThomas Richter */ 2886dde6429SThomas Richter static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, 2896dde6429SThomas Richter struct list_head *alist) 2906dde6429SThomas Richter { 2916dde6429SThomas Richter struct perf_pmu_alias *a; 2926dde6429SThomas Richter 2936dde6429SThomas Richter list_for_each_entry(a, alist, list) { 2946dde6429SThomas Richter if (!strcasecmp(newalias->name, a->name)) { 2956dde6429SThomas Richter perf_pmu_update_alias(a, newalias); 2966dde6429SThomas Richter perf_pmu_free_alias(newalias); 2976dde6429SThomas Richter return true; 2986dde6429SThomas Richter } 2996dde6429SThomas Richter } 3006dde6429SThomas Richter return false; 3016dde6429SThomas Richter } 3026dde6429SThomas Richter 30370c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 304fedb2b51SAndi Kleen char *desc, char *val, 305fedb2b51SAndi Kleen char *long_desc, char *topic, 30600636c3bSAndi Kleen char *unit, char *perpkg, 30796284814SAndi Kleen char *metric_expr, 30896284814SAndi Kleen char *metric_name) 309a6146d50SZheng Yan { 3100c24d6fbSThomas Richter struct parse_events_term *term; 3115c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 312a6146d50SZheng Yan int ret; 313fedb2b51SAndi Kleen int num; 3140c24d6fbSThomas Richter char newval[256]; 315a6146d50SZheng Yan 316a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 317a6146d50SZheng Yan if (!alias) 318a6146d50SZheng Yan return -ENOMEM; 319a6146d50SZheng Yan 320a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 321410136f5SStephane Eranian alias->scale = 1.0; 322410136f5SStephane Eranian alias->unit[0] = '\0'; 323044330c1SMatt Fleming alias->per_pkg = false; 32484530920SStephane Eranian alias->snapshot = false; 325410136f5SStephane Eranian 32670c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 327a6146d50SZheng Yan if (ret) { 32870c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 329a6146d50SZheng Yan free(alias); 330a6146d50SZheng Yan return ret; 331a6146d50SZheng Yan } 332a6146d50SZheng Yan 3330c24d6fbSThomas Richter /* Scan event and remove leading zeroes, spaces, newlines, some 3340c24d6fbSThomas Richter * platforms have terms specified as 3350c24d6fbSThomas Richter * event=0x0091 (read from files ../<PMU>/events/<FILE> 3360c24d6fbSThomas Richter * and terms specified as event=0x91 (read from JSON files). 3370c24d6fbSThomas Richter * 3380c24d6fbSThomas Richter * Rebuild string to make alias->str member comparable. 3390c24d6fbSThomas Richter */ 3400c24d6fbSThomas Richter memset(newval, 0, sizeof(newval)); 3410c24d6fbSThomas Richter ret = 0; 3420c24d6fbSThomas Richter list_for_each_entry(term, &alias->terms, list) { 3430c24d6fbSThomas Richter if (ret) 3440c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3450c24d6fbSThomas Richter ","); 3460c24d6fbSThomas Richter if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 3470c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3480c24d6fbSThomas Richter "%s=%#x", term->config, term->val.num); 3490c24d6fbSThomas Richter else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 3500c24d6fbSThomas Richter ret += scnprintf(newval + ret, sizeof(newval) - ret, 3510c24d6fbSThomas Richter "%s=%s", term->config, term->val.str); 3520c24d6fbSThomas Richter } 3530c24d6fbSThomas Richter 354a6146d50SZheng Yan alias->name = strdup(name); 35570c646e0SSukadev Bhattiprolu if (dir) { 356410136f5SStephane Eranian /* 357410136f5SStephane Eranian * load unit name and scale if available 358410136f5SStephane Eranian */ 359410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 360410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 361044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 3621d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 36370c646e0SSukadev Bhattiprolu } 364410136f5SStephane Eranian 36500636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 36696284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 36708e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 368c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 369c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 370dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 371fedb2b51SAndi Kleen if (unit) { 372fedb2b51SAndi Kleen if (convert_scale(unit, &unit, &alias->scale) < 0) 373fedb2b51SAndi Kleen return -1; 374fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 375fedb2b51SAndi Kleen } 376fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 3770c24d6fbSThomas Richter alias->str = strdup(newval); 378f2361024SAndi Kleen 3796dde6429SThomas Richter if (!perf_pmu_merge_alias(alias, list)) 380a6146d50SZheng Yan list_add_tail(&alias->list, list); 381410136f5SStephane Eranian 382a6146d50SZheng Yan return 0; 383a6146d50SZheng Yan } 384a6146d50SZheng Yan 38570c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 38670c646e0SSukadev Bhattiprolu { 38770c646e0SSukadev Bhattiprolu char buf[256]; 38870c646e0SSukadev Bhattiprolu int ret; 38970c646e0SSukadev Bhattiprolu 39070c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 39170c646e0SSukadev Bhattiprolu if (ret == 0) 39270c646e0SSukadev Bhattiprolu return -EINVAL; 39370c646e0SSukadev Bhattiprolu 39470c646e0SSukadev Bhattiprolu buf[ret] = 0; 39570c646e0SSukadev Bhattiprolu 396ea23ac73SThomas Richter /* Remove trailing newline from sysfs file */ 397ea23ac73SThomas Richter rtrim(buf); 398ea23ac73SThomas Richter 399fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 40096284814SAndi Kleen NULL, NULL, NULL); 40170c646e0SSukadev Bhattiprolu } 40270c646e0SSukadev Bhattiprolu 40346441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 40446441bdcSMatt Fleming { 40546441bdcSMatt Fleming size_t len; 40646441bdcSMatt Fleming 40746441bdcSMatt Fleming len = strlen(name); 40846441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 40946441bdcSMatt Fleming return true; 41046441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 41146441bdcSMatt Fleming return true; 412044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 413044330c1SMatt Fleming return true; 4141d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 4151d9e446bSJiri Olsa return true; 41646441bdcSMatt Fleming 41746441bdcSMatt Fleming return false; 41846441bdcSMatt Fleming } 41946441bdcSMatt Fleming 420a6146d50SZheng Yan /* 421a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 422a6146d50SZheng Yan * specified in 'dir' parameter. 423a6146d50SZheng Yan */ 424a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 425a6146d50SZheng Yan { 426a6146d50SZheng Yan struct dirent *evt_ent; 427a6146d50SZheng Yan DIR *event_dir; 428a6146d50SZheng Yan 429a6146d50SZheng Yan event_dir = opendir(dir); 430a6146d50SZheng Yan if (!event_dir) 431a6146d50SZheng Yan return -EINVAL; 432a6146d50SZheng Yan 433940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 434a6146d50SZheng Yan char path[PATH_MAX]; 435a6146d50SZheng Yan char *name = evt_ent->d_name; 436a6146d50SZheng Yan FILE *file; 437a6146d50SZheng Yan 438a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 439a6146d50SZheng Yan continue; 440a6146d50SZheng Yan 441410136f5SStephane Eranian /* 44246441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 443410136f5SStephane Eranian */ 44446441bdcSMatt Fleming if (pmu_alias_info_file(name)) 445410136f5SStephane Eranian continue; 446410136f5SStephane Eranian 44777f18153SJiri Olsa scnprintf(path, PATH_MAX, "%s/%s", dir, name); 448a6146d50SZheng Yan 449a6146d50SZheng Yan file = fopen(path, "r"); 450940db6dcSAndi Kleen if (!file) { 451940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 452940db6dcSAndi Kleen continue; 453940db6dcSAndi Kleen } 454410136f5SStephane Eranian 455940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 456940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 457a6146d50SZheng Yan fclose(file); 458a6146d50SZheng Yan } 459a6146d50SZheng Yan 460a6146d50SZheng Yan closedir(event_dir); 461940db6dcSAndi Kleen return 0; 462a6146d50SZheng Yan } 463a6146d50SZheng Yan 464a6146d50SZheng Yan /* 465a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 466a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 467a6146d50SZheng Yan */ 468b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 469a6146d50SZheng Yan { 470a6146d50SZheng Yan struct stat st; 471a6146d50SZheng Yan char path[PATH_MAX]; 472cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 473a6146d50SZheng Yan 474a6146d50SZheng Yan if (!sysfs) 475a6146d50SZheng Yan return -1; 476a6146d50SZheng Yan 477a6146d50SZheng Yan snprintf(path, PATH_MAX, 478a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 479a6146d50SZheng Yan 480a6146d50SZheng Yan if (stat(path, &st) < 0) 4813fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 482a6146d50SZheng Yan 483a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 484a6146d50SZheng Yan return -1; 485a6146d50SZheng Yan 486a6146d50SZheng Yan return 0; 487a6146d50SZheng Yan } 488a6146d50SZheng Yan 4895c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 490a6146d50SZheng Yan struct list_head *terms) 491a6146d50SZheng Yan { 4927c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 493a6146d50SZheng Yan LIST_HEAD(list); 494a6146d50SZheng Yan int ret; 495a6146d50SZheng Yan 496a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 4977c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 498a6146d50SZheng Yan if (ret) { 499682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 500a6146d50SZheng Yan return ret; 501a6146d50SZheng Yan } 502c2f1ceadSAndi Kleen /* 503c2f1ceadSAndi Kleen * Weak terms don't override command line options, 504c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 505c2f1ceadSAndi Kleen */ 506c2f1ceadSAndi Kleen cloned->weak = true; 5077c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 508a6146d50SZheng Yan } 509a6146d50SZheng Yan list_splice(&list, terms); 510a6146d50SZheng Yan return 0; 511a6146d50SZheng Yan } 512a6146d50SZheng Yan 513cd82a32eSJiri Olsa /* 514cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 515cd82a32eSJiri Olsa * located at: 516cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 517cd82a32eSJiri Olsa */ 518b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 519cd82a32eSJiri Olsa { 520cd82a32eSJiri Olsa struct stat st; 521cd82a32eSJiri Olsa char path[PATH_MAX]; 522cd82a32eSJiri Olsa FILE *file; 523cd82a32eSJiri Olsa int ret = 0; 524cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 525cd82a32eSJiri Olsa 526cd82a32eSJiri Olsa if (!sysfs) 527cd82a32eSJiri Olsa return -1; 528cd82a32eSJiri Olsa 529cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 53050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 531cd82a32eSJiri Olsa 532cd82a32eSJiri Olsa if (stat(path, &st) < 0) 533cd82a32eSJiri Olsa return -1; 534cd82a32eSJiri Olsa 535cd82a32eSJiri Olsa file = fopen(path, "r"); 536cd82a32eSJiri Olsa if (!file) 537cd82a32eSJiri Olsa return -EINVAL; 538cd82a32eSJiri Olsa 539cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 540cd82a32eSJiri Olsa ret = -1; 541cd82a32eSJiri Olsa 542cd82a32eSJiri Olsa fclose(file); 543cd82a32eSJiri Olsa return ret; 544cd82a32eSJiri Olsa } 545cd82a32eSJiri Olsa 54650a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 54750a9667cSRobert Richter static void pmu_read_sysfs(void) 54850a9667cSRobert Richter { 54950a9667cSRobert Richter char path[PATH_MAX]; 55050a9667cSRobert Richter DIR *dir; 55150a9667cSRobert Richter struct dirent *dent; 552cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 55350a9667cSRobert Richter 55450a9667cSRobert Richter if (!sysfs) 55550a9667cSRobert Richter return; 55650a9667cSRobert Richter 55750a9667cSRobert Richter snprintf(path, PATH_MAX, 55850a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 55950a9667cSRobert Richter 56050a9667cSRobert Richter dir = opendir(path); 56150a9667cSRobert Richter if (!dir) 56250a9667cSRobert Richter return; 56350a9667cSRobert Richter 56450a9667cSRobert Richter while ((dent = readdir(dir))) { 56550a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 56650a9667cSRobert Richter continue; 56750a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 56850a9667cSRobert Richter perf_pmu__find(dent->d_name); 56950a9667cSRobert Richter } 57050a9667cSRobert Richter 57150a9667cSRobert Richter closedir(dir); 57250a9667cSRobert Richter } 57350a9667cSRobert Richter 57466ec1191SMark Rutland static struct cpu_map *__pmu_cpumask(const char *path) 57566ec1191SMark Rutland { 57666ec1191SMark Rutland FILE *file; 57766ec1191SMark Rutland struct cpu_map *cpus; 57866ec1191SMark Rutland 57966ec1191SMark Rutland file = fopen(path, "r"); 58066ec1191SMark Rutland if (!file) 58166ec1191SMark Rutland return NULL; 58266ec1191SMark Rutland 58366ec1191SMark Rutland cpus = cpu_map__read(file); 58466ec1191SMark Rutland fclose(file); 58566ec1191SMark Rutland return cpus; 58666ec1191SMark Rutland } 58766ec1191SMark Rutland 58866ec1191SMark Rutland /* 58966ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 59066ec1191SMark Rutland * may have a "cpus" file. 59166ec1191SMark Rutland */ 59266ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 59366ec1191SMark Rutland #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 59466ec1191SMark Rutland 595b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 5967ae92e74SYan, Zheng { 5977ae92e74SYan, Zheng char path[PATH_MAX]; 5987ae92e74SYan, Zheng struct cpu_map *cpus; 599cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 6007e3fcffeSMark Rutland const char *templates[] = { 60166ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 60266ec1191SMark Rutland CPUS_TEMPLATE_CPU, 6037e3fcffeSMark Rutland NULL 6047e3fcffeSMark Rutland }; 6057e3fcffeSMark Rutland const char **template; 6067ae92e74SYan, Zheng 6077ae92e74SYan, Zheng if (!sysfs) 6087ae92e74SYan, Zheng return NULL; 6097ae92e74SYan, Zheng 6107e3fcffeSMark Rutland for (template = templates; *template; template++) { 6117e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 61266ec1191SMark Rutland cpus = __pmu_cpumask(path); 61366ec1191SMark Rutland if (cpus) 61466ec1191SMark Rutland return cpus; 6157e3fcffeSMark Rutland } 6167ae92e74SYan, Zheng 6177ae92e74SYan, Zheng return NULL; 61866ec1191SMark Rutland } 6197ae92e74SYan, Zheng 62066ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 62166ec1191SMark Rutland { 62266ec1191SMark Rutland char path[PATH_MAX]; 62366ec1191SMark Rutland struct cpu_map *cpus; 62466ec1191SMark Rutland const char *sysfs = sysfs__mountpoint(); 6257ae92e74SYan, Zheng 62666ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 62766ec1191SMark Rutland cpus = __pmu_cpumask(path); 62866ec1191SMark Rutland cpu_map__put(cpus); 62966ec1191SMark Rutland 63066ec1191SMark Rutland return !!cpus; 6317ae92e74SYan, Zheng } 6327ae92e74SYan, Zheng 633933f82ffSSukadev Bhattiprolu /* 63414b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 635292c34c1SKan Liang * platforms. 636292c34c1SKan Liang * Looking for possible sysfs files to identify the arm core device. 63714b22ae0SGanapatrao Kulkarni */ 638292c34c1SKan Liang static int is_arm_pmu_core(const char *name) 63914b22ae0SGanapatrao Kulkarni { 64014b22ae0SGanapatrao Kulkarni struct stat st; 64114b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 64214b22ae0SGanapatrao Kulkarni const char *sysfs = sysfs__mountpoint(); 64314b22ae0SGanapatrao Kulkarni 64414b22ae0SGanapatrao Kulkarni if (!sysfs) 64514b22ae0SGanapatrao Kulkarni return 0; 64614b22ae0SGanapatrao Kulkarni 64714b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (specific to arm) */ 64814b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", 64914b22ae0SGanapatrao Kulkarni sysfs, name); 65014b22ae0SGanapatrao Kulkarni if (stat(path, &st) == 0) 65114b22ae0SGanapatrao Kulkarni return 1; 65214b22ae0SGanapatrao Kulkarni 65314b22ae0SGanapatrao Kulkarni return 0; 65414b22ae0SGanapatrao Kulkarni } 65514b22ae0SGanapatrao Kulkarni 65654e32dc0SGanapatrao Kulkarni static char *perf_pmu__getcpuid(struct perf_pmu *pmu) 657d77ade9fSAndi Kleen { 658d77ade9fSAndi Kleen char *cpuid; 659d77ade9fSAndi Kleen static bool printed; 660d77ade9fSAndi Kleen 661d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 662d77ade9fSAndi Kleen if (cpuid) 663d77ade9fSAndi Kleen cpuid = strdup(cpuid); 664d77ade9fSAndi Kleen if (!cpuid) 66554e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 666d77ade9fSAndi Kleen if (!cpuid) 667d77ade9fSAndi Kleen return NULL; 668d77ade9fSAndi Kleen 669d77ade9fSAndi Kleen if (!printed) { 670d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 671d77ade9fSAndi Kleen printed = true; 672d77ade9fSAndi Kleen } 673d77ade9fSAndi Kleen return cpuid; 674d77ade9fSAndi Kleen } 675d77ade9fSAndi Kleen 67654e32dc0SGanapatrao Kulkarni struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu) 677d77ade9fSAndi Kleen { 678d77ade9fSAndi Kleen struct pmu_events_map *map; 67954e32dc0SGanapatrao Kulkarni char *cpuid = perf_pmu__getcpuid(pmu); 680d77ade9fSAndi Kleen int i; 681d77ade9fSAndi Kleen 682de3d0f12SGanapatrao Kulkarni /* on some platforms which uses cpus map, cpuid can be NULL for 683de3d0f12SGanapatrao Kulkarni * PMUs other than CORE PMUs. 684de3d0f12SGanapatrao Kulkarni */ 685de3d0f12SGanapatrao Kulkarni if (!cpuid) 686de3d0f12SGanapatrao Kulkarni return NULL; 687de3d0f12SGanapatrao Kulkarni 688d77ade9fSAndi Kleen i = 0; 689d77ade9fSAndi Kleen for (;;) { 690d77ade9fSAndi Kleen map = &pmu_events_map[i++]; 691d77ade9fSAndi Kleen if (!map->table) { 692d77ade9fSAndi Kleen map = NULL; 693d77ade9fSAndi Kleen break; 694d77ade9fSAndi Kleen } 695d77ade9fSAndi Kleen 6964cb7d3ecSThomas Richter if (!strcmp_cpuid_str(map->cpuid, cpuid)) 697d77ade9fSAndi Kleen break; 698d77ade9fSAndi Kleen } 699d77ade9fSAndi Kleen free(cpuid); 700d77ade9fSAndi Kleen return map; 701d77ade9fSAndi Kleen } 702d77ade9fSAndi Kleen 703933f82ffSSukadev Bhattiprolu /* 704933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 705933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 706933f82ffSSukadev Bhattiprolu * as aliases. 707933f82ffSSukadev Bhattiprolu */ 70854e32dc0SGanapatrao Kulkarni static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 709933f82ffSSukadev Bhattiprolu { 710933f82ffSSukadev Bhattiprolu int i; 711933f82ffSSukadev Bhattiprolu struct pmu_events_map *map; 712933f82ffSSukadev Bhattiprolu struct pmu_event *pe; 71354e32dc0SGanapatrao Kulkarni const char *name = pmu->name; 714292c34c1SKan Liang const char *pname; 715933f82ffSSukadev Bhattiprolu 71654e32dc0SGanapatrao Kulkarni map = perf_pmu__find_map(pmu); 717d77ade9fSAndi Kleen if (!map) 718933f82ffSSukadev Bhattiprolu return; 719933f82ffSSukadev Bhattiprolu 720933f82ffSSukadev Bhattiprolu /* 721933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 722933f82ffSSukadev Bhattiprolu */ 723933f82ffSSukadev Bhattiprolu i = 0; 724933f82ffSSukadev Bhattiprolu while (1) { 725fedb2b51SAndi Kleen 726933f82ffSSukadev Bhattiprolu pe = &map->table[i++]; 727b18f3e36SAndi Kleen if (!pe->name) { 728b18f3e36SAndi Kleen if (pe->metric_group || pe->metric_name) 729b18f3e36SAndi Kleen continue; 730933f82ffSSukadev Bhattiprolu break; 731b18f3e36SAndi Kleen } 732933f82ffSSukadev Bhattiprolu 733292c34c1SKan Liang if (!is_arm_pmu_core(name)) { 734292c34c1SKan Liang pname = pe->pmu ? pe->pmu : "cpu"; 735ea1fa48cSThomas Richter if (strcmp(pname, name)) 73614b22ae0SGanapatrao Kulkarni continue; 73714b22ae0SGanapatrao Kulkarni } 738fedb2b51SAndi Kleen 739933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 740933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 741c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 742fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 74300636c3bSAndi Kleen (char *)pe->unit, (char *)pe->perpkg, 74496284814SAndi Kleen (char *)pe->metric_expr, 74596284814SAndi Kleen (char *)pe->metric_name); 746933f82ffSSukadev Bhattiprolu } 747933f82ffSSukadev Bhattiprolu } 748933f82ffSSukadev Bhattiprolu 749c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 750dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 751dc0a6202SAdrian Hunter { 752dc0a6202SAdrian Hunter return NULL; 753dc0a6202SAdrian Hunter } 754dc0a6202SAdrian Hunter 755*90a86bdeSJiri Olsa static int pmu_max_precise(const char *name) 756*90a86bdeSJiri Olsa { 757*90a86bdeSJiri Olsa char path[PATH_MAX]; 758*90a86bdeSJiri Olsa int max_precise = -1; 759*90a86bdeSJiri Olsa 760*90a86bdeSJiri Olsa scnprintf(path, PATH_MAX, 761*90a86bdeSJiri Olsa "bus/event_source/devices/%s/caps/max_precise", 762*90a86bdeSJiri Olsa name); 763*90a86bdeSJiri Olsa 764*90a86bdeSJiri Olsa sysfs__read_int(path, &max_precise); 765*90a86bdeSJiri Olsa return max_precise; 766*90a86bdeSJiri Olsa } 767*90a86bdeSJiri Olsa 768b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 769cd82a32eSJiri Olsa { 770cd82a32eSJiri Olsa struct perf_pmu *pmu; 771cd82a32eSJiri Olsa LIST_HEAD(format); 772a6146d50SZheng Yan LIST_HEAD(aliases); 773cd82a32eSJiri Olsa __u32 type; 774cd82a32eSJiri Olsa 775cd82a32eSJiri Olsa /* 776cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 777cd82a32eSJiri Olsa * type value and format definitions. Load both right 778cd82a32eSJiri Olsa * now. 779cd82a32eSJiri Olsa */ 780cd82a32eSJiri Olsa if (pmu_format(name, &format)) 781cd82a32eSJiri Olsa return NULL; 782cd82a32eSJiri Olsa 78315b22ed3SAndi Kleen /* 78415b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 78515b22ed3SAndi Kleen */ 78615b22ed3SAndi Kleen if (pmu_type(name, &type)) 78715b22ed3SAndi Kleen return NULL; 78815b22ed3SAndi Kleen 7893fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 7903fded963SJiri Olsa return NULL; 7913fded963SJiri Olsa 792cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 793cd82a32eSJiri Olsa if (!pmu) 794cd82a32eSJiri Olsa return NULL; 795cd82a32eSJiri Olsa 7967ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 79754e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 79854e32dc0SGanapatrao Kulkarni pmu->type = type; 79966ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 800*90a86bdeSJiri Olsa pmu->max_precise = pmu_max_precise(name); 80154e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 80266ec1191SMark Rutland 803cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 804a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 805cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 806a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 8079bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 808dc0a6202SAdrian Hunter 809dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 810dc0a6202SAdrian Hunter 811cd82a32eSJiri Olsa return pmu; 812cd82a32eSJiri Olsa } 813cd82a32eSJiri Olsa 814b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 815cd82a32eSJiri Olsa { 816cd82a32eSJiri Olsa struct perf_pmu *pmu; 817cd82a32eSJiri Olsa 818cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 819cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 820cd82a32eSJiri Olsa return pmu; 821cd82a32eSJiri Olsa 822cd82a32eSJiri Olsa return NULL; 823cd82a32eSJiri Olsa } 824cd82a32eSJiri Olsa 82550a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 82650a9667cSRobert Richter { 82750a9667cSRobert Richter /* 82850a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 82950a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 83050a9667cSRobert Richter */ 83150a9667cSRobert Richter if (!pmu) { 83250a9667cSRobert Richter pmu_read_sysfs(); 83350a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 83450a9667cSRobert Richter } 83550a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 83650a9667cSRobert Richter return pmu; 83750a9667cSRobert Richter return NULL; 83850a9667cSRobert Richter } 83950a9667cSRobert Richter 840b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 841cd82a32eSJiri Olsa { 842cd82a32eSJiri Olsa struct perf_pmu *pmu; 843cd82a32eSJiri Olsa 844cd82a32eSJiri Olsa /* 845cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 846cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 847cd82a32eSJiri Olsa * the pmu format definitions. 848cd82a32eSJiri Olsa */ 849cd82a32eSJiri Olsa pmu = pmu_find(name); 850cd82a32eSJiri Olsa if (pmu) 851cd82a32eSJiri Olsa return pmu; 852cd82a32eSJiri Olsa 853cd82a32eSJiri Olsa return pmu_lookup(name); 854cd82a32eSJiri Olsa } 855cd82a32eSJiri Olsa 8565c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 85709ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 858cd82a32eSJiri Olsa { 8595c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 860cd82a32eSJiri Olsa 861cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 862cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 863cd82a32eSJiri Olsa return format; 864cd82a32eSJiri Olsa 865cd82a32eSJiri Olsa return NULL; 866cd82a32eSJiri Olsa } 867cd82a32eSJiri Olsa 86809ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 86909ff6071SAdrian Hunter { 87009ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 87109ff6071SAdrian Hunter __u64 bits = 0; 87209ff6071SAdrian Hunter int fbit; 87309ff6071SAdrian Hunter 87409ff6071SAdrian Hunter if (!format) 87509ff6071SAdrian Hunter return 0; 87609ff6071SAdrian Hunter 87709ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 87809ff6071SAdrian Hunter bits |= 1ULL << fbit; 87909ff6071SAdrian Hunter 88009ff6071SAdrian Hunter return bits; 88109ff6071SAdrian Hunter } 88209ff6071SAdrian Hunter 883cd82a32eSJiri Olsa /* 884dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 885cd82a32eSJiri Olsa * and unformated value (value parameter). 886cd82a32eSJiri Olsa */ 887dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 888dc0a6202SAdrian Hunter bool zero) 889cd82a32eSJiri Olsa { 890cd82a32eSJiri Olsa unsigned long fbit, vbit; 891cd82a32eSJiri Olsa 892cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 893cd82a32eSJiri Olsa 894cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 895cd82a32eSJiri Olsa continue; 896cd82a32eSJiri Olsa 897dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 898dc0a6202SAdrian Hunter *v |= (1llu << fbit); 899dc0a6202SAdrian Hunter else if (zero) 900dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 901cd82a32eSJiri Olsa } 902cd82a32eSJiri Olsa } 903cd82a32eSJiri Olsa 9040efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 9050efe6b67SAdrian Hunter { 9061b9caa10SJiri Olsa int w; 9070efe6b67SAdrian Hunter 9081b9caa10SJiri Olsa w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); 9091b9caa10SJiri Olsa if (!w) 9101b9caa10SJiri Olsa return 0; 9111b9caa10SJiri Olsa if (w < 64) 9121b9caa10SJiri Olsa return (1ULL << w) - 1; 9131b9caa10SJiri Olsa return -1; 9140efe6b67SAdrian Hunter } 9150efe6b67SAdrian Hunter 916cd82a32eSJiri Olsa /* 917688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 918688d4dfcSCody P Schafer * in the remaining terms. 919688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 920688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 921688d4dfcSCody P Schafer * in a config string) later on in the term list. 922688d4dfcSCody P Schafer */ 923688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 924688d4dfcSCody P Schafer struct list_head *head_terms, 925688d4dfcSCody P Schafer __u64 *value) 926688d4dfcSCody P Schafer { 927688d4dfcSCody P Schafer struct parse_events_term *t; 928688d4dfcSCody P Schafer 929688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 930688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 931688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 932688d4dfcSCody P Schafer t->used = true; 933688d4dfcSCody P Schafer *value = t->val.num; 934688d4dfcSCody P Schafer return 0; 935688d4dfcSCody P Schafer } 936688d4dfcSCody P Schafer } 937688d4dfcSCody P Schafer } 938688d4dfcSCody P Schafer 939bb963e16SNamhyung Kim if (verbose > 0) 940688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 941688d4dfcSCody P Schafer 942688d4dfcSCody P Schafer return -1; 943688d4dfcSCody P Schafer } 944688d4dfcSCody P Schafer 945ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 946e64b020bSJiri Olsa { 947e64b020bSJiri Olsa struct perf_pmu_format *format; 94811db4e29SMasami Hiramatsu char *str = NULL; 94911db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 950e64b020bSJiri Olsa unsigned i = 0; 951e64b020bSJiri Olsa 952ffeb883eSHe Kuang if (!formats) 953e64b020bSJiri Olsa return NULL; 954e64b020bSJiri Olsa 955e64b020bSJiri Olsa /* sysfs exported terms */ 956ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 95711db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 95811db4e29SMasami Hiramatsu goto error; 959e64b020bSJiri Olsa 960ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 96111db4e29SMasami Hiramatsu error: 962ffeb883eSHe Kuang strbuf_release(&buf); 963e64b020bSJiri Olsa 964e64b020bSJiri Olsa return str; 965e64b020bSJiri Olsa } 966e64b020bSJiri Olsa 967688d4dfcSCody P Schafer /* 968cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 96988aca8d9SCody P Schafer * user input data - term parameter. 970cd82a32eSJiri Olsa */ 971cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 972cd82a32eSJiri Olsa struct perf_event_attr *attr, 973dc0a6202SAdrian Hunter struct parse_events_term *term, 974688d4dfcSCody P Schafer struct list_head *head_terms, 975e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 976cd82a32eSJiri Olsa { 9775c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 978cd82a32eSJiri Olsa __u64 *vp; 9790efe6b67SAdrian Hunter __u64 val, max_val; 980cd82a32eSJiri Olsa 981cd82a32eSJiri Olsa /* 982688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 983688d4dfcSCody P Schafer * skip it in normal eval. 984688d4dfcSCody P Schafer */ 985688d4dfcSCody P Schafer if (term->used) 986688d4dfcSCody P Schafer return 0; 987688d4dfcSCody P Schafer 988688d4dfcSCody P Schafer /* 989cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 990cd82a32eSJiri Olsa * to be done for them. 991cd82a32eSJiri Olsa */ 992cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 993cd82a32eSJiri Olsa return 0; 994cd82a32eSJiri Olsa 995cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 996688d4dfcSCody P Schafer if (!format) { 997bb963e16SNamhyung Kim if (verbose > 0) 998688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 999e64b020bSJiri Olsa if (err) { 1000ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 1001ffeb883eSHe Kuang 1002e64b020bSJiri Olsa err->idx = term->err_term; 1003e64b020bSJiri Olsa err->str = strdup("unknown term"); 1004ffeb883eSHe Kuang err->help = parse_events_formats_error_string(pmu_term); 1005ffeb883eSHe Kuang free(pmu_term); 1006e64b020bSJiri Olsa } 1007cd82a32eSJiri Olsa return -EINVAL; 1008688d4dfcSCody P Schafer } 1009cd82a32eSJiri Olsa 1010cd82a32eSJiri Olsa switch (format->value) { 1011cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 1012cd82a32eSJiri Olsa vp = &attr->config; 1013cd82a32eSJiri Olsa break; 1014cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 1015cd82a32eSJiri Olsa vp = &attr->config1; 1016cd82a32eSJiri Olsa break; 1017cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 1018cd82a32eSJiri Olsa vp = &attr->config2; 1019cd82a32eSJiri Olsa break; 1020cd82a32eSJiri Olsa default: 1021cd82a32eSJiri Olsa return -EINVAL; 1022cd82a32eSJiri Olsa } 1023cd82a32eSJiri Olsa 102416fa7e82SJiri Olsa /* 1025688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 1026688d4dfcSCody P Schafer * using event parameters. 102716fa7e82SJiri Olsa */ 102899e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 102999e7138eSJiri Olsa if (term->no_value && 103099e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 103199e7138eSJiri Olsa if (err) { 103299e7138eSJiri Olsa err->idx = term->err_val; 103399e7138eSJiri Olsa err->str = strdup("no value assigned for term"); 103499e7138eSJiri Olsa } 103599e7138eSJiri Olsa return -EINVAL; 103699e7138eSJiri Olsa } 103799e7138eSJiri Olsa 1038688d4dfcSCody P Schafer val = term->val.num; 103999e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1040688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 1041bb963e16SNamhyung Kim if (verbose > 0) { 1042688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 1043688d4dfcSCody P Schafer term->config, term->val.str); 1044e64b020bSJiri Olsa } 1045e64b020bSJiri Olsa if (err) { 1046e64b020bSJiri Olsa err->idx = term->err_val; 1047e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 1048e64b020bSJiri Olsa } 1049688d4dfcSCody P Schafer return -EINVAL; 1050688d4dfcSCody P Schafer } 1051688d4dfcSCody P Schafer 1052688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 1053688d4dfcSCody P Schafer return -EINVAL; 1054688d4dfcSCody P Schafer } else 1055688d4dfcSCody P Schafer return -EINVAL; 1056688d4dfcSCody P Schafer 10570efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 10580efe6b67SAdrian Hunter if (val > max_val) { 10590efe6b67SAdrian Hunter if (err) { 10600efe6b67SAdrian Hunter err->idx = term->err_val; 10610efe6b67SAdrian Hunter if (asprintf(&err->str, 10620efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 10630efe6b67SAdrian Hunter (unsigned long long)max_val) < 0) 10640efe6b67SAdrian Hunter err->str = strdup("value too big for format"); 10650efe6b67SAdrian Hunter return -EINVAL; 10660efe6b67SAdrian Hunter } 10670efe6b67SAdrian Hunter /* 10680efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 10690efe6b67SAdrian Hunter * silently truncated. 10700efe6b67SAdrian Hunter */ 10710efe6b67SAdrian Hunter } 10720efe6b67SAdrian Hunter 1073688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1074cd82a32eSJiri Olsa return 0; 1075cd82a32eSJiri Olsa } 1076cd82a32eSJiri Olsa 1077cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 1078cff7f956SJiri Olsa struct perf_event_attr *attr, 1079dc0a6202SAdrian Hunter struct list_head *head_terms, 1080e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1081cd82a32eSJiri Olsa { 10826cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1083cd82a32eSJiri Olsa 1084688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 1085e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 1086e64b020bSJiri Olsa zero, err)) 1087cd82a32eSJiri Olsa return -EINVAL; 1088688d4dfcSCody P Schafer } 1089cd82a32eSJiri Olsa 1090cd82a32eSJiri Olsa return 0; 1091cd82a32eSJiri Olsa } 1092cd82a32eSJiri Olsa 1093cd82a32eSJiri Olsa /* 1094cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1095cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1096cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1097cd82a32eSJiri Olsa */ 1098cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1099e64b020bSJiri Olsa struct list_head *head_terms, 1100e64b020bSJiri Olsa struct parse_events_error *err) 1101cd82a32eSJiri Olsa { 1102dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1103dc0a6202SAdrian Hunter 1104cd82a32eSJiri Olsa attr->type = pmu->type; 1105e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 1106e64b020bSJiri Olsa zero, err); 1107cd82a32eSJiri Olsa } 1108cd82a32eSJiri Olsa 11095c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 11106cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1111a6146d50SZheng Yan { 11125c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1113a6146d50SZheng Yan char *name; 1114a6146d50SZheng Yan 1115a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1116a6146d50SZheng Yan return NULL; 1117a6146d50SZheng Yan 1118a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1119a6146d50SZheng Yan if (term->val.num != 1) 1120a6146d50SZheng Yan return NULL; 1121a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1122a6146d50SZheng Yan return NULL; 1123a6146d50SZheng Yan name = term->config; 1124a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1125a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1126a6146d50SZheng Yan return NULL; 1127a6146d50SZheng Yan name = term->val.str; 1128a6146d50SZheng Yan } else { 1129a6146d50SZheng Yan return NULL; 1130a6146d50SZheng Yan } 1131a6146d50SZheng Yan 1132a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1133a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1134a6146d50SZheng Yan return alias; 1135a6146d50SZheng Yan } 1136a6146d50SZheng Yan return NULL; 1137a6146d50SZheng Yan } 1138a6146d50SZheng Yan 1139410136f5SStephane Eranian 11401d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 11411d9e446bSJiri Olsa struct perf_pmu_info *info) 1142410136f5SStephane Eranian { 1143410136f5SStephane Eranian /* 1144410136f5SStephane Eranian * Only one term in event definition can 11451d9e446bSJiri Olsa * define unit, scale and snapshot, fail 11461d9e446bSJiri Olsa * if there's more than one. 1147410136f5SStephane Eranian */ 1148b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 11491d9e446bSJiri Olsa (info->scale && alias->scale) || 11501d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1151410136f5SStephane Eranian return -EINVAL; 1152410136f5SStephane Eranian 1153b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 11541d9e446bSJiri Olsa info->unit = alias->unit; 1155410136f5SStephane Eranian 1156410136f5SStephane Eranian if (alias->scale) 11571d9e446bSJiri Olsa info->scale = alias->scale; 11581d9e446bSJiri Olsa 11591d9e446bSJiri Olsa if (alias->snapshot) 11601d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1161410136f5SStephane Eranian 1162410136f5SStephane Eranian return 0; 1163410136f5SStephane Eranian } 1164410136f5SStephane Eranian 1165a6146d50SZheng Yan /* 1166a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1167a6146d50SZheng Yan * defined for the alias 1168a6146d50SZheng Yan */ 1169410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 117046441bdcSMatt Fleming struct perf_pmu_info *info) 1171a6146d50SZheng Yan { 11726cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 11735c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1174a6146d50SZheng Yan int ret; 1175a6146d50SZheng Yan 1176044330c1SMatt Fleming info->per_pkg = false; 1177044330c1SMatt Fleming 11788a398897SStephane Eranian /* 11798a398897SStephane Eranian * Mark unit and scale as not set 11808a398897SStephane Eranian * (different from default values, see below) 11818a398897SStephane Eranian */ 118246441bdcSMatt Fleming info->unit = NULL; 118346441bdcSMatt Fleming info->scale = 0.0; 11841d9e446bSJiri Olsa info->snapshot = false; 118537932c18SAndi Kleen info->metric_expr = NULL; 118696284814SAndi Kleen info->metric_name = NULL; 1187410136f5SStephane Eranian 1188a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1189a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1190a6146d50SZheng Yan if (!alias) 1191a6146d50SZheng Yan continue; 1192a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1193a6146d50SZheng Yan if (ret) 1194a6146d50SZheng Yan return ret; 1195410136f5SStephane Eranian 11961d9e446bSJiri Olsa ret = check_info_data(alias, info); 1197410136f5SStephane Eranian if (ret) 1198410136f5SStephane Eranian return ret; 1199410136f5SStephane Eranian 1200044330c1SMatt Fleming if (alias->per_pkg) 1201044330c1SMatt Fleming info->per_pkg = true; 120237932c18SAndi Kleen info->metric_expr = alias->metric_expr; 120396284814SAndi Kleen info->metric_name = alias->metric_name; 1204044330c1SMatt Fleming 1205a6146d50SZheng Yan list_del(&term->list); 1206a6146d50SZheng Yan free(term); 1207a6146d50SZheng Yan } 12088a398897SStephane Eranian 12098a398897SStephane Eranian /* 12108a398897SStephane Eranian * if no unit or scale foundin aliases, then 12118a398897SStephane Eranian * set defaults as for evsel 12128a398897SStephane Eranian * unit cannot left to NULL 12138a398897SStephane Eranian */ 121446441bdcSMatt Fleming if (info->unit == NULL) 121546441bdcSMatt Fleming info->unit = ""; 12168a398897SStephane Eranian 121746441bdcSMatt Fleming if (info->scale == 0.0) 121846441bdcSMatt Fleming info->scale = 1.0; 12198a398897SStephane Eranian 1220a6146d50SZheng Yan return 0; 1221a6146d50SZheng Yan } 1222a6146d50SZheng Yan 1223cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1224cd82a32eSJiri Olsa int config, unsigned long *bits) 1225cd82a32eSJiri Olsa { 12265c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1227cd82a32eSJiri Olsa 1228cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1229cd82a32eSJiri Olsa if (!format) 1230cd82a32eSJiri Olsa return -ENOMEM; 1231cd82a32eSJiri Olsa 1232cd82a32eSJiri Olsa format->name = strdup(name); 1233cd82a32eSJiri Olsa format->value = config; 1234cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1235cd82a32eSJiri Olsa 1236cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1237cd82a32eSJiri Olsa return 0; 1238cd82a32eSJiri Olsa } 1239cd82a32eSJiri Olsa 1240cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1241cd82a32eSJiri Olsa { 1242cd82a32eSJiri Olsa long b; 1243cd82a32eSJiri Olsa 1244cd82a32eSJiri Olsa if (!to) 1245cd82a32eSJiri Olsa to = from; 1246cd82a32eSJiri Olsa 124715268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1248cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1249cd82a32eSJiri Olsa set_bit(b, bits); 1250cd82a32eSJiri Olsa } 1251dc098b35SAndi Kleen 1252aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1253aaea3617SCody P Schafer { 1254aaea3617SCody P Schafer if (b > a) 1255aaea3617SCody P Schafer return 0; 1256aaea3617SCody P Schafer return a - b; 1257aaea3617SCody P Schafer } 1258aaea3617SCody P Schafer 1259dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1260dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1261dc098b35SAndi Kleen { 1262aaea3617SCody P Schafer struct parse_events_term *term; 1263aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1264aaea3617SCody P Schafer 1265aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1266aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1267aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1268aaea3617SCody P Schafer ",%s=%s", term->config, 1269aaea3617SCody P Schafer term->val.str); 1270aaea3617SCody P Schafer } 1271aaea3617SCody P Schafer 1272aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1273aaea3617SCody P Schafer buf[used] = '/'; 1274aaea3617SCody P Schafer used++; 1275aaea3617SCody P Schafer } 1276aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1277aaea3617SCody P Schafer buf[used] = '\0'; 1278aaea3617SCody P Schafer used++; 1279aaea3617SCody P Schafer } else 1280aaea3617SCody P Schafer buf[len - 1] = '\0'; 1281aaea3617SCody P Schafer 1282dc098b35SAndi Kleen return buf; 1283dc098b35SAndi Kleen } 1284dc098b35SAndi Kleen 1285dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1286dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1287dc098b35SAndi Kleen { 1288dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1289dc098b35SAndi Kleen return buf; 1290dc098b35SAndi Kleen } 1291dc098b35SAndi Kleen 1292dd5f1036SAndi Kleen struct sevent { 129308e60ed1SAndi Kleen char *name; 129408e60ed1SAndi Kleen char *desc; 1295dd5f1036SAndi Kleen char *topic; 1296f2361024SAndi Kleen char *str; 1297f2361024SAndi Kleen char *pmu; 12987f372a63SAndi Kleen char *metric_expr; 129996284814SAndi Kleen char *metric_name; 130008e60ed1SAndi Kleen }; 130108e60ed1SAndi Kleen 1302dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1303dc098b35SAndi Kleen { 1304dd5f1036SAndi Kleen const struct sevent *as = a; 1305dd5f1036SAndi Kleen const struct sevent *bs = b; 130608e60ed1SAndi Kleen 130708e60ed1SAndi Kleen /* Put extra events last */ 130808e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 130908e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1310dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1311dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1312dd5f1036SAndi Kleen 1313dd5f1036SAndi Kleen if (n) 1314dd5f1036SAndi Kleen return n; 1315dd5f1036SAndi Kleen } 131608e60ed1SAndi Kleen return strcmp(as->name, bs->name); 131708e60ed1SAndi Kleen } 131808e60ed1SAndi Kleen 131908e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 132008e60ed1SAndi Kleen { 132108e60ed1SAndi Kleen int column = start; 132208e60ed1SAndi Kleen int n; 132308e60ed1SAndi Kleen 132408e60ed1SAndi Kleen while (*s) { 132508e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 132608e60ed1SAndi Kleen 132708e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 132808e60ed1SAndi Kleen printf("\n%*s", start, ""); 132908e60ed1SAndi Kleen column = start + corr; 133008e60ed1SAndi Kleen } 133108e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 133208e60ed1SAndi Kleen if (n <= 0) 133308e60ed1SAndi Kleen break; 133408e60ed1SAndi Kleen s += wlen; 133508e60ed1SAndi Kleen column += n; 1336aa4beb10STaeung Song s = ltrim(s); 133708e60ed1SAndi Kleen } 1338dc098b35SAndi Kleen } 1339dc098b35SAndi Kleen 1340c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1341bf874fcfSAndi Kleen bool long_desc, bool details_flag) 1342dc098b35SAndi Kleen { 1343dc098b35SAndi Kleen struct perf_pmu *pmu; 1344dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1345dc098b35SAndi Kleen char buf[1024]; 1346dc098b35SAndi Kleen int printed = 0; 1347dc098b35SAndi Kleen int len, j; 1348dd5f1036SAndi Kleen struct sevent *aliases; 134908e60ed1SAndi Kleen int numdesc = 0; 135061eb2eb4SAndi Kleen int columns = pager_get_columns(); 1351dd5f1036SAndi Kleen char *topic = NULL; 1352dc098b35SAndi Kleen 1353dc098b35SAndi Kleen pmu = NULL; 1354dc098b35SAndi Kleen len = 0; 135542634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1356dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1357dc098b35SAndi Kleen len++; 135842634bc7SAdrian Hunter if (pmu->selectable) 135942634bc7SAdrian Hunter len++; 136042634bc7SAdrian Hunter } 1361dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1362dc098b35SAndi Kleen if (!aliases) 13637e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1364dc098b35SAndi Kleen pmu = NULL; 1365dc098b35SAndi Kleen j = 0; 136642634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1367dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 136808e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 136908e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1370dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1371dc098b35SAndi Kleen 1372dc098b35SAndi Kleen if (event_glob != NULL && 137338d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 137438d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 137567bdc35fSAndi Kleen event_glob)) || 137667bdc35fSAndi Kleen (alias->topic && 137767bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1378dc098b35SAndi Kleen continue; 13797e4772dcSArnaldo Carvalho de Melo 138008e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 13817e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 13827e4772dcSArnaldo Carvalho de Melo 138308e60ed1SAndi Kleen aliases[j].name = name; 138408e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 138508e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 138608e60ed1SAndi Kleen sizeof(buf), 138708e60ed1SAndi Kleen pmu, alias); 138808e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 138908e60ed1SAndi Kleen if (!aliases[j].name) 13907e4772dcSArnaldo Carvalho de Melo goto out_enomem; 139108e60ed1SAndi Kleen 1392c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1393c8d6828aSSukadev Bhattiprolu alias->desc; 1394dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1395f2361024SAndi Kleen aliases[j].str = alias->str; 1396f2361024SAndi Kleen aliases[j].pmu = pmu->name; 13977f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 139896284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1399dc098b35SAndi Kleen j++; 1400dc098b35SAndi Kleen } 1401fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1402fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 14037e4772dcSArnaldo Carvalho de Melo char *s; 14047e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 14057e4772dcSArnaldo Carvalho de Melo goto out_enomem; 140608e60ed1SAndi Kleen aliases[j].name = s; 140742634bc7SAdrian Hunter j++; 140842634bc7SAdrian Hunter } 140942634bc7SAdrian Hunter } 1410dc098b35SAndi Kleen len = j; 1411dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1412dc098b35SAndi Kleen for (j = 0; j < len; j++) { 141315b22ed3SAndi Kleen /* Skip duplicates */ 141415b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 141515b22ed3SAndi Kleen continue; 1416dc098b35SAndi Kleen if (name_only) { 141708e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1418dc098b35SAndi Kleen continue; 1419dc098b35SAndi Kleen } 14201c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 142108e60ed1SAndi Kleen if (numdesc++ == 0) 142208e60ed1SAndi Kleen printf("\n"); 1423dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1424dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1425dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1426dd5f1036SAndi Kleen aliases[j].topic); 1427dd5f1036SAndi Kleen topic = aliases[j].topic; 1428dd5f1036SAndi Kleen } 142908e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 143008e60ed1SAndi Kleen printf("%*s", 8, "["); 143108e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 143208e60ed1SAndi Kleen printf("]\n"); 1433bf874fcfSAndi Kleen if (details_flag) { 14347f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 143596284814SAndi Kleen if (aliases[j].metric_name) 143696284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 14377f372a63SAndi Kleen if (aliases[j].metric_expr) 14387f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 14397f372a63SAndi Kleen putchar('\n'); 14407f372a63SAndi Kleen } 144108e60ed1SAndi Kleen } else 144208e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1443dc098b35SAndi Kleen printed++; 1444dc098b35SAndi Kleen } 1445dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1446dc098b35SAndi Kleen printf("\n"); 14477e4772dcSArnaldo Carvalho de Melo out_free: 14487e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 144908e60ed1SAndi Kleen zfree(&aliases[j].name); 14507e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 14517e4772dcSArnaldo Carvalho de Melo return; 14527e4772dcSArnaldo Carvalho de Melo 14537e4772dcSArnaldo Carvalho de Melo out_enomem: 14547e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 14557e4772dcSArnaldo Carvalho de Melo if (aliases) 14567e4772dcSArnaldo Carvalho de Melo goto out_free; 1457dc098b35SAndi Kleen } 14584cabc3d1SAndi Kleen 14594cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 14604cabc3d1SAndi Kleen { 14614cabc3d1SAndi Kleen struct perf_pmu *pmu; 14624cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 14634cabc3d1SAndi Kleen 14644cabc3d1SAndi Kleen pmu = NULL; 14654cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 14664cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 14674cabc3d1SAndi Kleen continue; 14684cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 14694cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 14704cabc3d1SAndi Kleen return true; 14714cabc3d1SAndi Kleen } 14724cabc3d1SAndi Kleen return false; 14734cabc3d1SAndi Kleen } 14747d4bdab5SAdrian Hunter 14757d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 14767d4bdab5SAdrian Hunter { 14777d4bdab5SAdrian Hunter struct stat st; 14787d4bdab5SAdrian Hunter char path[PATH_MAX]; 14797d4bdab5SAdrian Hunter const char *sysfs; 14807d4bdab5SAdrian Hunter 14817d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 14827d4bdab5SAdrian Hunter if (!sysfs) 14837d4bdab5SAdrian Hunter return NULL; 14847d4bdab5SAdrian Hunter 14857d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 14867d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 14877d4bdab5SAdrian Hunter 14887d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 14897d4bdab5SAdrian Hunter return NULL; 14907d4bdab5SAdrian Hunter 14917d4bdab5SAdrian Hunter return fopen(path, "r"); 14927d4bdab5SAdrian Hunter } 14937d4bdab5SAdrian Hunter 14947d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 14957d4bdab5SAdrian Hunter ...) 14967d4bdab5SAdrian Hunter { 14977d4bdab5SAdrian Hunter va_list args; 14987d4bdab5SAdrian Hunter FILE *file; 14997d4bdab5SAdrian Hunter int ret = EOF; 15007d4bdab5SAdrian Hunter 15017d4bdab5SAdrian Hunter va_start(args, fmt); 15027d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 15037d4bdab5SAdrian Hunter if (file) { 15047d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 15057d4bdab5SAdrian Hunter fclose(file); 15067d4bdab5SAdrian Hunter } 15077d4bdab5SAdrian Hunter va_end(args); 15087d4bdab5SAdrian Hunter return ret; 15097d4bdab5SAdrian Hunter } 1510