1cd82a32eSJiri Olsa #include <linux/list.h> 2c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 3cd82a32eSJiri Olsa #include <sys/types.h> 4a43783aeSArnaldo Carvalho de Melo #include <errno.h> 57a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 6cd82a32eSJiri Olsa #include <unistd.h> 7cd82a32eSJiri Olsa #include <stdio.h> 8dc0a6202SAdrian Hunter #include <stdbool.h> 97d4bdab5SAdrian Hunter #include <stdarg.h> 10cd82a32eSJiri Olsa #include <dirent.h> 11cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 12410136f5SStephane Eranian #include <locale.h> 13cd82a32eSJiri Olsa #include "util.h" 14cd82a32eSJiri Olsa #include "pmu.h" 15cd82a32eSJiri Olsa #include "parse-events.h" 167ae92e74SYan, Zheng #include "cpumap.h" 17933f82ffSSukadev Bhattiprolu #include "header.h" 18933f82ffSSukadev Bhattiprolu #include "pmu-events/pmu-events.h" 1961eb2eb4SAndi Kleen #include "cache.h" 20a067558eSArnaldo Carvalho de Melo #include "string2.h" 21cd82a32eSJiri Olsa 22ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 23ab1bf653SArnaldo Carvalho de Melo char *name; 24ab1bf653SArnaldo Carvalho de Melo int value; 25ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 26ab1bf653SArnaldo Carvalho de Melo struct list_head list; 27ab1bf653SArnaldo Carvalho de Melo }; 28ab1bf653SArnaldo Carvalho de Melo 2950a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 3050a9667cSRobert Richter 31cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 32cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 33cd82a32eSJiri Olsa 34cd82a32eSJiri Olsa static LIST_HEAD(pmus); 35cd82a32eSJiri Olsa 36cd82a32eSJiri Olsa /* 37cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 38cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 39cd82a32eSJiri Olsa */ 40cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 41cd82a32eSJiri Olsa { 42cd82a32eSJiri Olsa struct dirent *evt_ent; 43cd82a32eSJiri Olsa DIR *format_dir; 44cd82a32eSJiri Olsa int ret = 0; 45cd82a32eSJiri Olsa 46cd82a32eSJiri Olsa format_dir = opendir(dir); 47cd82a32eSJiri Olsa if (!format_dir) 48cd82a32eSJiri Olsa return -EINVAL; 49cd82a32eSJiri Olsa 50cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 51cd82a32eSJiri Olsa char path[PATH_MAX]; 52cd82a32eSJiri Olsa char *name = evt_ent->d_name; 53cd82a32eSJiri Olsa FILE *file; 54cd82a32eSJiri Olsa 55cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 56cd82a32eSJiri Olsa continue; 57cd82a32eSJiri Olsa 58cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 59cd82a32eSJiri Olsa 60cd82a32eSJiri Olsa ret = -EINVAL; 61cd82a32eSJiri Olsa file = fopen(path, "r"); 62cd82a32eSJiri Olsa if (!file) 63cd82a32eSJiri Olsa break; 64cd82a32eSJiri Olsa 65cd82a32eSJiri Olsa perf_pmu_in = file; 66cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 67cd82a32eSJiri Olsa fclose(file); 68cd82a32eSJiri Olsa } 69cd82a32eSJiri Olsa 70cd82a32eSJiri Olsa closedir(format_dir); 71cd82a32eSJiri Olsa return ret; 72cd82a32eSJiri Olsa } 73cd82a32eSJiri Olsa 74cd82a32eSJiri Olsa /* 75cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 76cd82a32eSJiri Olsa * located at: 77cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 78cd82a32eSJiri Olsa */ 79b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 80cd82a32eSJiri Olsa { 81cd82a32eSJiri Olsa struct stat st; 82cd82a32eSJiri Olsa char path[PATH_MAX]; 83cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 84cd82a32eSJiri Olsa 85cd82a32eSJiri Olsa if (!sysfs) 86cd82a32eSJiri Olsa return -1; 87cd82a32eSJiri Olsa 88cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 8950a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 90cd82a32eSJiri Olsa 91cd82a32eSJiri Olsa if (stat(path, &st) < 0) 929bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 93cd82a32eSJiri Olsa 94cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 95cd82a32eSJiri Olsa return -1; 96cd82a32eSJiri Olsa 97cd82a32eSJiri Olsa return 0; 98cd82a32eSJiri Olsa } 99cd82a32eSJiri Olsa 100d02fc6bcSAndi Kleen static int convert_scale(const char *scale, char **end, double *sval) 101d02fc6bcSAndi Kleen { 102d02fc6bcSAndi Kleen char *lc; 103d02fc6bcSAndi Kleen int ret = 0; 104d02fc6bcSAndi Kleen 105d02fc6bcSAndi Kleen /* 106d02fc6bcSAndi Kleen * save current locale 107d02fc6bcSAndi Kleen */ 108d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 109d02fc6bcSAndi Kleen 110d02fc6bcSAndi Kleen /* 111d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 112d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 113d02fc6bcSAndi Kleen * call below. 114d02fc6bcSAndi Kleen */ 115d02fc6bcSAndi Kleen lc = strdup(lc); 116d02fc6bcSAndi Kleen if (!lc) { 117d02fc6bcSAndi Kleen ret = -ENOMEM; 118d02fc6bcSAndi Kleen goto out; 119d02fc6bcSAndi Kleen } 120d02fc6bcSAndi Kleen 121d02fc6bcSAndi Kleen /* 122d02fc6bcSAndi Kleen * force to C locale to ensure kernel 123d02fc6bcSAndi Kleen * scale string is converted correctly. 124d02fc6bcSAndi Kleen * kernel uses default C locale. 125d02fc6bcSAndi Kleen */ 126d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 127d02fc6bcSAndi Kleen 128d02fc6bcSAndi Kleen *sval = strtod(scale, end); 129d02fc6bcSAndi Kleen 130d02fc6bcSAndi Kleen out: 131d02fc6bcSAndi Kleen /* restore locale */ 132d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 133d02fc6bcSAndi Kleen free(lc); 134d02fc6bcSAndi Kleen return ret; 135d02fc6bcSAndi Kleen } 136d02fc6bcSAndi Kleen 137410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 138410136f5SStephane Eranian { 139410136f5SStephane Eranian struct stat st; 140410136f5SStephane Eranian ssize_t sret; 141410136f5SStephane Eranian char scale[128]; 142410136f5SStephane Eranian int fd, ret = -1; 143410136f5SStephane Eranian char path[PATH_MAX]; 144410136f5SStephane Eranian 145410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 146410136f5SStephane Eranian 147410136f5SStephane Eranian fd = open(path, O_RDONLY); 148410136f5SStephane Eranian if (fd == -1) 149410136f5SStephane Eranian return -1; 150410136f5SStephane Eranian 151410136f5SStephane Eranian if (fstat(fd, &st) < 0) 152410136f5SStephane Eranian goto error; 153410136f5SStephane Eranian 154410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 155410136f5SStephane Eranian if (sret < 0) 156410136f5SStephane Eranian goto error; 157410136f5SStephane Eranian 1589ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1599ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1609ecae065SMadhavan Srinivasan else 161410136f5SStephane Eranian scale[sret] = '\0'; 1629ecae065SMadhavan Srinivasan 163d02fc6bcSAndi Kleen ret = convert_scale(scale, NULL, &alias->scale); 164410136f5SStephane Eranian error: 165410136f5SStephane Eranian close(fd); 166410136f5SStephane Eranian return ret; 167410136f5SStephane Eranian } 168410136f5SStephane Eranian 169410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 170410136f5SStephane Eranian { 171410136f5SStephane Eranian char path[PATH_MAX]; 172410136f5SStephane Eranian ssize_t sret; 173410136f5SStephane Eranian int fd; 174410136f5SStephane Eranian 175410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 176410136f5SStephane Eranian 177410136f5SStephane Eranian fd = open(path, O_RDONLY); 178410136f5SStephane Eranian if (fd == -1) 179410136f5SStephane Eranian return -1; 180410136f5SStephane Eranian 181410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 182410136f5SStephane Eranian if (sret < 0) 183410136f5SStephane Eranian goto error; 184410136f5SStephane Eranian 185410136f5SStephane Eranian close(fd); 186410136f5SStephane Eranian 1879ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1889ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1899ecae065SMadhavan Srinivasan else 190410136f5SStephane Eranian alias->unit[sret] = '\0'; 191410136f5SStephane Eranian 192410136f5SStephane Eranian return 0; 193410136f5SStephane Eranian error: 194410136f5SStephane Eranian close(fd); 195410136f5SStephane Eranian alias->unit[0] = '\0'; 196410136f5SStephane Eranian return -1; 197410136f5SStephane Eranian } 198410136f5SStephane Eranian 199044330c1SMatt Fleming static int 200044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 201044330c1SMatt Fleming { 202044330c1SMatt Fleming char path[PATH_MAX]; 203044330c1SMatt Fleming int fd; 204044330c1SMatt Fleming 205044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 206044330c1SMatt Fleming 207044330c1SMatt Fleming fd = open(path, O_RDONLY); 208044330c1SMatt Fleming if (fd == -1) 209044330c1SMatt Fleming return -1; 210044330c1SMatt Fleming 211044330c1SMatt Fleming close(fd); 212044330c1SMatt Fleming 213044330c1SMatt Fleming alias->per_pkg = true; 214044330c1SMatt Fleming return 0; 215044330c1SMatt Fleming } 216044330c1SMatt Fleming 2171d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2181d9e446bSJiri Olsa char *dir, char *name) 2191d9e446bSJiri Olsa { 2201d9e446bSJiri Olsa char path[PATH_MAX]; 2211d9e446bSJiri Olsa int fd; 2221d9e446bSJiri Olsa 2231d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2241d9e446bSJiri Olsa 2251d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2261d9e446bSJiri Olsa if (fd == -1) 2271d9e446bSJiri Olsa return -1; 2281d9e446bSJiri Olsa 2291d9e446bSJiri Olsa alias->snapshot = true; 2301d9e446bSJiri Olsa close(fd); 2311d9e446bSJiri Olsa return 0; 2321d9e446bSJiri Olsa } 2331d9e446bSJiri Olsa 23470c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 235fedb2b51SAndi Kleen char *desc, char *val, 236fedb2b51SAndi Kleen char *long_desc, char *topic, 23700636c3bSAndi Kleen char *unit, char *perpkg, 23896284814SAndi Kleen char *metric_expr, 23996284814SAndi Kleen char *metric_name) 240a6146d50SZheng Yan { 2415c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 242a6146d50SZheng Yan int ret; 243fedb2b51SAndi Kleen int num; 244a6146d50SZheng Yan 245a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 246a6146d50SZheng Yan if (!alias) 247a6146d50SZheng Yan return -ENOMEM; 248a6146d50SZheng Yan 249a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 250410136f5SStephane Eranian alias->scale = 1.0; 251410136f5SStephane Eranian alias->unit[0] = '\0'; 252044330c1SMatt Fleming alias->per_pkg = false; 25384530920SStephane Eranian alias->snapshot = false; 254410136f5SStephane Eranian 25570c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 256a6146d50SZheng Yan if (ret) { 25770c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 258a6146d50SZheng Yan free(alias); 259a6146d50SZheng Yan return ret; 260a6146d50SZheng Yan } 261a6146d50SZheng Yan 262a6146d50SZheng Yan alias->name = strdup(name); 26370c646e0SSukadev Bhattiprolu if (dir) { 264410136f5SStephane Eranian /* 265410136f5SStephane Eranian * load unit name and scale if available 266410136f5SStephane Eranian */ 267410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 268410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 269044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2701d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 27170c646e0SSukadev Bhattiprolu } 272410136f5SStephane Eranian 27300636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 27496284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 27508e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 276c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 277c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 278dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 279fedb2b51SAndi Kleen if (unit) { 280fedb2b51SAndi Kleen if (convert_scale(unit, &unit, &alias->scale) < 0) 281fedb2b51SAndi Kleen return -1; 282fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 283fedb2b51SAndi Kleen } 284fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 285f2361024SAndi Kleen alias->str = strdup(val); 286f2361024SAndi Kleen 287a6146d50SZheng Yan list_add_tail(&alias->list, list); 288410136f5SStephane Eranian 289a6146d50SZheng Yan return 0; 290a6146d50SZheng Yan } 291a6146d50SZheng Yan 29270c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 29370c646e0SSukadev Bhattiprolu { 29470c646e0SSukadev Bhattiprolu char buf[256]; 29570c646e0SSukadev Bhattiprolu int ret; 29670c646e0SSukadev Bhattiprolu 29770c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 29870c646e0SSukadev Bhattiprolu if (ret == 0) 29970c646e0SSukadev Bhattiprolu return -EINVAL; 30070c646e0SSukadev Bhattiprolu 30170c646e0SSukadev Bhattiprolu buf[ret] = 0; 30270c646e0SSukadev Bhattiprolu 303fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 30496284814SAndi Kleen NULL, NULL, NULL); 30570c646e0SSukadev Bhattiprolu } 30670c646e0SSukadev Bhattiprolu 30746441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 30846441bdcSMatt Fleming { 30946441bdcSMatt Fleming size_t len; 31046441bdcSMatt Fleming 31146441bdcSMatt Fleming len = strlen(name); 31246441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 31346441bdcSMatt Fleming return true; 31446441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 31546441bdcSMatt Fleming return true; 316044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 317044330c1SMatt Fleming return true; 3181d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 3191d9e446bSJiri Olsa return true; 32046441bdcSMatt Fleming 32146441bdcSMatt Fleming return false; 32246441bdcSMatt Fleming } 32346441bdcSMatt Fleming 324a6146d50SZheng Yan /* 325a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 326a6146d50SZheng Yan * specified in 'dir' parameter. 327a6146d50SZheng Yan */ 328a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 329a6146d50SZheng Yan { 330a6146d50SZheng Yan struct dirent *evt_ent; 331a6146d50SZheng Yan DIR *event_dir; 332a6146d50SZheng Yan 333a6146d50SZheng Yan event_dir = opendir(dir); 334a6146d50SZheng Yan if (!event_dir) 335a6146d50SZheng Yan return -EINVAL; 336a6146d50SZheng Yan 337940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 338a6146d50SZheng Yan char path[PATH_MAX]; 339a6146d50SZheng Yan char *name = evt_ent->d_name; 340a6146d50SZheng Yan FILE *file; 341a6146d50SZheng Yan 342a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 343a6146d50SZheng Yan continue; 344a6146d50SZheng Yan 345410136f5SStephane Eranian /* 34646441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 347410136f5SStephane Eranian */ 34846441bdcSMatt Fleming if (pmu_alias_info_file(name)) 349410136f5SStephane Eranian continue; 350410136f5SStephane Eranian 351a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 352a6146d50SZheng Yan 353a6146d50SZheng Yan file = fopen(path, "r"); 354940db6dcSAndi Kleen if (!file) { 355940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 356940db6dcSAndi Kleen continue; 357940db6dcSAndi Kleen } 358410136f5SStephane Eranian 359940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 360940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 361a6146d50SZheng Yan fclose(file); 362a6146d50SZheng Yan } 363a6146d50SZheng Yan 364a6146d50SZheng Yan closedir(event_dir); 365940db6dcSAndi Kleen return 0; 366a6146d50SZheng Yan } 367a6146d50SZheng Yan 368a6146d50SZheng Yan /* 369a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 370a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 371a6146d50SZheng Yan */ 372b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 373a6146d50SZheng Yan { 374a6146d50SZheng Yan struct stat st; 375a6146d50SZheng Yan char path[PATH_MAX]; 376cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 377a6146d50SZheng Yan 378a6146d50SZheng Yan if (!sysfs) 379a6146d50SZheng Yan return -1; 380a6146d50SZheng Yan 381a6146d50SZheng Yan snprintf(path, PATH_MAX, 382a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 383a6146d50SZheng Yan 384a6146d50SZheng Yan if (stat(path, &st) < 0) 3853fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 386a6146d50SZheng Yan 387a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 388a6146d50SZheng Yan return -1; 389a6146d50SZheng Yan 390a6146d50SZheng Yan return 0; 391a6146d50SZheng Yan } 392a6146d50SZheng Yan 3935c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 394a6146d50SZheng Yan struct list_head *terms) 395a6146d50SZheng Yan { 3967c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 397a6146d50SZheng Yan LIST_HEAD(list); 398a6146d50SZheng Yan int ret; 399a6146d50SZheng Yan 400a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 4017c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 402a6146d50SZheng Yan if (ret) { 403682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 404a6146d50SZheng Yan return ret; 405a6146d50SZheng Yan } 4067c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 407a6146d50SZheng Yan } 408a6146d50SZheng Yan list_splice(&list, terms); 409a6146d50SZheng Yan return 0; 410a6146d50SZheng Yan } 411a6146d50SZheng Yan 412cd82a32eSJiri Olsa /* 413cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 414cd82a32eSJiri Olsa * located at: 415cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 416cd82a32eSJiri Olsa */ 417b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 418cd82a32eSJiri Olsa { 419cd82a32eSJiri Olsa struct stat st; 420cd82a32eSJiri Olsa char path[PATH_MAX]; 421cd82a32eSJiri Olsa FILE *file; 422cd82a32eSJiri Olsa int ret = 0; 423cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 424cd82a32eSJiri Olsa 425cd82a32eSJiri Olsa if (!sysfs) 426cd82a32eSJiri Olsa return -1; 427cd82a32eSJiri Olsa 428cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 42950a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 430cd82a32eSJiri Olsa 431cd82a32eSJiri Olsa if (stat(path, &st) < 0) 432cd82a32eSJiri Olsa return -1; 433cd82a32eSJiri Olsa 434cd82a32eSJiri Olsa file = fopen(path, "r"); 435cd82a32eSJiri Olsa if (!file) 436cd82a32eSJiri Olsa return -EINVAL; 437cd82a32eSJiri Olsa 438cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 439cd82a32eSJiri Olsa ret = -1; 440cd82a32eSJiri Olsa 441cd82a32eSJiri Olsa fclose(file); 442cd82a32eSJiri Olsa return ret; 443cd82a32eSJiri Olsa } 444cd82a32eSJiri Olsa 44550a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 44650a9667cSRobert Richter static void pmu_read_sysfs(void) 44750a9667cSRobert Richter { 44850a9667cSRobert Richter char path[PATH_MAX]; 44950a9667cSRobert Richter DIR *dir; 45050a9667cSRobert Richter struct dirent *dent; 451cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 45250a9667cSRobert Richter 45350a9667cSRobert Richter if (!sysfs) 45450a9667cSRobert Richter return; 45550a9667cSRobert Richter 45650a9667cSRobert Richter snprintf(path, PATH_MAX, 45750a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 45850a9667cSRobert Richter 45950a9667cSRobert Richter dir = opendir(path); 46050a9667cSRobert Richter if (!dir) 46150a9667cSRobert Richter return; 46250a9667cSRobert Richter 46350a9667cSRobert Richter while ((dent = readdir(dir))) { 46450a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 46550a9667cSRobert Richter continue; 46650a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 46750a9667cSRobert Richter perf_pmu__find(dent->d_name); 46850a9667cSRobert Richter } 46950a9667cSRobert Richter 47050a9667cSRobert Richter closedir(dir); 47150a9667cSRobert Richter } 47250a9667cSRobert Richter 47366ec1191SMark Rutland static struct cpu_map *__pmu_cpumask(const char *path) 47466ec1191SMark Rutland { 47566ec1191SMark Rutland FILE *file; 47666ec1191SMark Rutland struct cpu_map *cpus; 47766ec1191SMark Rutland 47866ec1191SMark Rutland file = fopen(path, "r"); 47966ec1191SMark Rutland if (!file) 48066ec1191SMark Rutland return NULL; 48166ec1191SMark Rutland 48266ec1191SMark Rutland cpus = cpu_map__read(file); 48366ec1191SMark Rutland fclose(file); 48466ec1191SMark Rutland return cpus; 48566ec1191SMark Rutland } 48666ec1191SMark Rutland 48766ec1191SMark Rutland /* 48866ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 48966ec1191SMark Rutland * may have a "cpus" file. 49066ec1191SMark Rutland */ 49166ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 49266ec1191SMark Rutland #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 49366ec1191SMark Rutland 494b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 4957ae92e74SYan, Zheng { 4967ae92e74SYan, Zheng char path[PATH_MAX]; 4977ae92e74SYan, Zheng struct cpu_map *cpus; 498cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 4997e3fcffeSMark Rutland const char *templates[] = { 50066ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 50166ec1191SMark Rutland CPUS_TEMPLATE_CPU, 5027e3fcffeSMark Rutland NULL 5037e3fcffeSMark Rutland }; 5047e3fcffeSMark Rutland const char **template; 5057ae92e74SYan, Zheng 5067ae92e74SYan, Zheng if (!sysfs) 5077ae92e74SYan, Zheng return NULL; 5087ae92e74SYan, Zheng 5097e3fcffeSMark Rutland for (template = templates; *template; template++) { 5107e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 51166ec1191SMark Rutland cpus = __pmu_cpumask(path); 51266ec1191SMark Rutland if (cpus) 51366ec1191SMark Rutland return cpus; 5147e3fcffeSMark Rutland } 5157ae92e74SYan, Zheng 5167ae92e74SYan, Zheng return NULL; 51766ec1191SMark Rutland } 5187ae92e74SYan, Zheng 51966ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 52066ec1191SMark Rutland { 52166ec1191SMark Rutland char path[PATH_MAX]; 52266ec1191SMark Rutland struct cpu_map *cpus; 52366ec1191SMark Rutland const char *sysfs = sysfs__mountpoint(); 5247ae92e74SYan, Zheng 52566ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 52666ec1191SMark Rutland cpus = __pmu_cpumask(path); 52766ec1191SMark Rutland cpu_map__put(cpus); 52866ec1191SMark Rutland 52966ec1191SMark Rutland return !!cpus; 5307ae92e74SYan, Zheng } 5317ae92e74SYan, Zheng 532933f82ffSSukadev Bhattiprolu /* 533933f82ffSSukadev Bhattiprolu * Return the CPU id as a raw string. 534933f82ffSSukadev Bhattiprolu * 535933f82ffSSukadev Bhattiprolu * Each architecture should provide a more precise id string that 536933f82ffSSukadev Bhattiprolu * can be use to match the architecture's "mapfile". 537933f82ffSSukadev Bhattiprolu */ 538933f82ffSSukadev Bhattiprolu char * __weak get_cpuid_str(void) 539933f82ffSSukadev Bhattiprolu { 540933f82ffSSukadev Bhattiprolu return NULL; 541933f82ffSSukadev Bhattiprolu } 542933f82ffSSukadev Bhattiprolu 543933f82ffSSukadev Bhattiprolu /* 544933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 545933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 546933f82ffSSukadev Bhattiprolu * as aliases. 547933f82ffSSukadev Bhattiprolu */ 548fedb2b51SAndi Kleen static void pmu_add_cpu_aliases(struct list_head *head, const char *name) 549933f82ffSSukadev Bhattiprolu { 550933f82ffSSukadev Bhattiprolu int i; 551933f82ffSSukadev Bhattiprolu struct pmu_events_map *map; 552933f82ffSSukadev Bhattiprolu struct pmu_event *pe; 553933f82ffSSukadev Bhattiprolu char *cpuid; 554fb967063SAndi Kleen static bool printed; 555933f82ffSSukadev Bhattiprolu 556fc06e2a5SAndi Kleen cpuid = getenv("PERF_CPUID"); 557fc06e2a5SAndi Kleen if (cpuid) 558fc06e2a5SAndi Kleen cpuid = strdup(cpuid); 559fc06e2a5SAndi Kleen if (!cpuid) 560933f82ffSSukadev Bhattiprolu cpuid = get_cpuid_str(); 561933f82ffSSukadev Bhattiprolu if (!cpuid) 562933f82ffSSukadev Bhattiprolu return; 563933f82ffSSukadev Bhattiprolu 564fb967063SAndi Kleen if (!printed) { 565fc06e2a5SAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 566fb967063SAndi Kleen printed = true; 567fb967063SAndi Kleen } 568fc06e2a5SAndi Kleen 569933f82ffSSukadev Bhattiprolu i = 0; 570933f82ffSSukadev Bhattiprolu while (1) { 571933f82ffSSukadev Bhattiprolu map = &pmu_events_map[i++]; 572933f82ffSSukadev Bhattiprolu if (!map->table) 573933f82ffSSukadev Bhattiprolu goto out; 574933f82ffSSukadev Bhattiprolu 575933f82ffSSukadev Bhattiprolu if (!strcmp(map->cpuid, cpuid)) 576933f82ffSSukadev Bhattiprolu break; 577933f82ffSSukadev Bhattiprolu } 578933f82ffSSukadev Bhattiprolu 579933f82ffSSukadev Bhattiprolu /* 580933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 581933f82ffSSukadev Bhattiprolu */ 582933f82ffSSukadev Bhattiprolu i = 0; 583933f82ffSSukadev Bhattiprolu while (1) { 584fedb2b51SAndi Kleen const char *pname; 585fedb2b51SAndi Kleen 586933f82ffSSukadev Bhattiprolu pe = &map->table[i++]; 587933f82ffSSukadev Bhattiprolu if (!pe->name) 588933f82ffSSukadev Bhattiprolu break; 589933f82ffSSukadev Bhattiprolu 590fedb2b51SAndi Kleen pname = pe->pmu ? pe->pmu : "cpu"; 591fedb2b51SAndi Kleen if (strncmp(pname, name, strlen(pname))) 592fedb2b51SAndi Kleen continue; 593fedb2b51SAndi Kleen 594933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 595933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 596c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 597fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 59800636c3bSAndi Kleen (char *)pe->unit, (char *)pe->perpkg, 59996284814SAndi Kleen (char *)pe->metric_expr, 60096284814SAndi Kleen (char *)pe->metric_name); 601933f82ffSSukadev Bhattiprolu } 602933f82ffSSukadev Bhattiprolu 603933f82ffSSukadev Bhattiprolu out: 604933f82ffSSukadev Bhattiprolu free(cpuid); 605933f82ffSSukadev Bhattiprolu } 606933f82ffSSukadev Bhattiprolu 607c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 608dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 609dc0a6202SAdrian Hunter { 610dc0a6202SAdrian Hunter return NULL; 611dc0a6202SAdrian Hunter } 612dc0a6202SAdrian Hunter 613b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 614cd82a32eSJiri Olsa { 615cd82a32eSJiri Olsa struct perf_pmu *pmu; 616cd82a32eSJiri Olsa LIST_HEAD(format); 617a6146d50SZheng Yan LIST_HEAD(aliases); 618cd82a32eSJiri Olsa __u32 type; 619cd82a32eSJiri Olsa 620cd82a32eSJiri Olsa /* 621cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 622cd82a32eSJiri Olsa * type value and format definitions. Load both right 623cd82a32eSJiri Olsa * now. 624cd82a32eSJiri Olsa */ 625cd82a32eSJiri Olsa if (pmu_format(name, &format)) 626cd82a32eSJiri Olsa return NULL; 627cd82a32eSJiri Olsa 62815b22ed3SAndi Kleen /* 62915b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 63015b22ed3SAndi Kleen */ 63115b22ed3SAndi Kleen if (pmu_type(name, &type)) 63215b22ed3SAndi Kleen return NULL; 63315b22ed3SAndi Kleen 6343fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 6353fded963SJiri Olsa return NULL; 6363fded963SJiri Olsa 637fedb2b51SAndi Kleen pmu_add_cpu_aliases(&aliases, name); 638cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 639cd82a32eSJiri Olsa if (!pmu) 640cd82a32eSJiri Olsa return NULL; 641cd82a32eSJiri Olsa 6427ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 6437ae92e74SYan, Zheng 64466ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 64566ec1191SMark Rutland 646cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 647a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 648cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 649a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 650cd82a32eSJiri Olsa pmu->name = strdup(name); 651cd82a32eSJiri Olsa pmu->type = type; 6529bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 653dc0a6202SAdrian Hunter 654dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 655dc0a6202SAdrian Hunter 656cd82a32eSJiri Olsa return pmu; 657cd82a32eSJiri Olsa } 658cd82a32eSJiri Olsa 659b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 660cd82a32eSJiri Olsa { 661cd82a32eSJiri Olsa struct perf_pmu *pmu; 662cd82a32eSJiri Olsa 663cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 664cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 665cd82a32eSJiri Olsa return pmu; 666cd82a32eSJiri Olsa 667cd82a32eSJiri Olsa return NULL; 668cd82a32eSJiri Olsa } 669cd82a32eSJiri Olsa 67050a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 67150a9667cSRobert Richter { 67250a9667cSRobert Richter /* 67350a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 67450a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 67550a9667cSRobert Richter */ 67650a9667cSRobert Richter if (!pmu) { 67750a9667cSRobert Richter pmu_read_sysfs(); 67850a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 67950a9667cSRobert Richter } 68050a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 68150a9667cSRobert Richter return pmu; 68250a9667cSRobert Richter return NULL; 68350a9667cSRobert Richter } 68450a9667cSRobert Richter 685b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 686cd82a32eSJiri Olsa { 687cd82a32eSJiri Olsa struct perf_pmu *pmu; 688cd82a32eSJiri Olsa 689cd82a32eSJiri Olsa /* 690cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 691cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 692cd82a32eSJiri Olsa * the pmu format definitions. 693cd82a32eSJiri Olsa */ 694cd82a32eSJiri Olsa pmu = pmu_find(name); 695cd82a32eSJiri Olsa if (pmu) 696cd82a32eSJiri Olsa return pmu; 697cd82a32eSJiri Olsa 698cd82a32eSJiri Olsa return pmu_lookup(name); 699cd82a32eSJiri Olsa } 700cd82a32eSJiri Olsa 7015c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 70209ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 703cd82a32eSJiri Olsa { 7045c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 705cd82a32eSJiri Olsa 706cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 707cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 708cd82a32eSJiri Olsa return format; 709cd82a32eSJiri Olsa 710cd82a32eSJiri Olsa return NULL; 711cd82a32eSJiri Olsa } 712cd82a32eSJiri Olsa 71309ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 71409ff6071SAdrian Hunter { 71509ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 71609ff6071SAdrian Hunter __u64 bits = 0; 71709ff6071SAdrian Hunter int fbit; 71809ff6071SAdrian Hunter 71909ff6071SAdrian Hunter if (!format) 72009ff6071SAdrian Hunter return 0; 72109ff6071SAdrian Hunter 72209ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 72309ff6071SAdrian Hunter bits |= 1ULL << fbit; 72409ff6071SAdrian Hunter 72509ff6071SAdrian Hunter return bits; 72609ff6071SAdrian Hunter } 72709ff6071SAdrian Hunter 728cd82a32eSJiri Olsa /* 729dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 730cd82a32eSJiri Olsa * and unformated value (value parameter). 731cd82a32eSJiri Olsa */ 732dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 733dc0a6202SAdrian Hunter bool zero) 734cd82a32eSJiri Olsa { 735cd82a32eSJiri Olsa unsigned long fbit, vbit; 736cd82a32eSJiri Olsa 737cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 738cd82a32eSJiri Olsa 739cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 740cd82a32eSJiri Olsa continue; 741cd82a32eSJiri Olsa 742dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 743dc0a6202SAdrian Hunter *v |= (1llu << fbit); 744dc0a6202SAdrian Hunter else if (zero) 745dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 746cd82a32eSJiri Olsa } 747cd82a32eSJiri Olsa } 748cd82a32eSJiri Olsa 7490efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 7500efe6b67SAdrian Hunter { 751ac0e2cd5SKan Liang __u64 w = 0; 752ac0e2cd5SKan Liang int fbit; 7530efe6b67SAdrian Hunter 754ac0e2cd5SKan Liang for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) 755ac0e2cd5SKan Liang w |= (1ULL << fbit); 756ac0e2cd5SKan Liang 757ac0e2cd5SKan Liang return w; 7580efe6b67SAdrian Hunter } 7590efe6b67SAdrian Hunter 760cd82a32eSJiri Olsa /* 761688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 762688d4dfcSCody P Schafer * in the remaining terms. 763688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 764688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 765688d4dfcSCody P Schafer * in a config string) later on in the term list. 766688d4dfcSCody P Schafer */ 767688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 768688d4dfcSCody P Schafer struct list_head *head_terms, 769688d4dfcSCody P Schafer __u64 *value) 770688d4dfcSCody P Schafer { 771688d4dfcSCody P Schafer struct parse_events_term *t; 772688d4dfcSCody P Schafer 773688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 774688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 775688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 776688d4dfcSCody P Schafer t->used = true; 777688d4dfcSCody P Schafer *value = t->val.num; 778688d4dfcSCody P Schafer return 0; 779688d4dfcSCody P Schafer } 780688d4dfcSCody P Schafer } 781688d4dfcSCody P Schafer } 782688d4dfcSCody P Schafer 783bb963e16SNamhyung Kim if (verbose > 0) 784688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 785688d4dfcSCody P Schafer 786688d4dfcSCody P Schafer return -1; 787688d4dfcSCody P Schafer } 788688d4dfcSCody P Schafer 789ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 790e64b020bSJiri Olsa { 791e64b020bSJiri Olsa struct perf_pmu_format *format; 79211db4e29SMasami Hiramatsu char *str = NULL; 79311db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 794e64b020bSJiri Olsa unsigned i = 0; 795e64b020bSJiri Olsa 796ffeb883eSHe Kuang if (!formats) 797e64b020bSJiri Olsa return NULL; 798e64b020bSJiri Olsa 799e64b020bSJiri Olsa /* sysfs exported terms */ 800ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 80111db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 80211db4e29SMasami Hiramatsu goto error; 803e64b020bSJiri Olsa 804ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 80511db4e29SMasami Hiramatsu error: 806ffeb883eSHe Kuang strbuf_release(&buf); 807e64b020bSJiri Olsa 808e64b020bSJiri Olsa return str; 809e64b020bSJiri Olsa } 810e64b020bSJiri Olsa 811688d4dfcSCody P Schafer /* 812cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 81388aca8d9SCody P Schafer * user input data - term parameter. 814cd82a32eSJiri Olsa */ 815cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 816cd82a32eSJiri Olsa struct perf_event_attr *attr, 817dc0a6202SAdrian Hunter struct parse_events_term *term, 818688d4dfcSCody P Schafer struct list_head *head_terms, 819e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 820cd82a32eSJiri Olsa { 8215c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 822cd82a32eSJiri Olsa __u64 *vp; 8230efe6b67SAdrian Hunter __u64 val, max_val; 824cd82a32eSJiri Olsa 825cd82a32eSJiri Olsa /* 826688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 827688d4dfcSCody P Schafer * skip it in normal eval. 828688d4dfcSCody P Schafer */ 829688d4dfcSCody P Schafer if (term->used) 830688d4dfcSCody P Schafer return 0; 831688d4dfcSCody P Schafer 832688d4dfcSCody P Schafer /* 833cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 834cd82a32eSJiri Olsa * to be done for them. 835cd82a32eSJiri Olsa */ 836cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 837cd82a32eSJiri Olsa return 0; 838cd82a32eSJiri Olsa 839cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 840688d4dfcSCody P Schafer if (!format) { 841bb963e16SNamhyung Kim if (verbose > 0) 842688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 843e64b020bSJiri Olsa if (err) { 844ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 845ffeb883eSHe Kuang 846e64b020bSJiri Olsa err->idx = term->err_term; 847e64b020bSJiri Olsa err->str = strdup("unknown term"); 848ffeb883eSHe Kuang err->help = parse_events_formats_error_string(pmu_term); 849ffeb883eSHe Kuang free(pmu_term); 850e64b020bSJiri Olsa } 851cd82a32eSJiri Olsa return -EINVAL; 852688d4dfcSCody P Schafer } 853cd82a32eSJiri Olsa 854cd82a32eSJiri Olsa switch (format->value) { 855cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 856cd82a32eSJiri Olsa vp = &attr->config; 857cd82a32eSJiri Olsa break; 858cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 859cd82a32eSJiri Olsa vp = &attr->config1; 860cd82a32eSJiri Olsa break; 861cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 862cd82a32eSJiri Olsa vp = &attr->config2; 863cd82a32eSJiri Olsa break; 864cd82a32eSJiri Olsa default: 865cd82a32eSJiri Olsa return -EINVAL; 866cd82a32eSJiri Olsa } 867cd82a32eSJiri Olsa 86816fa7e82SJiri Olsa /* 869688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 870688d4dfcSCody P Schafer * using event parameters. 87116fa7e82SJiri Olsa */ 87299e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 87399e7138eSJiri Olsa if (term->no_value && 87499e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 87599e7138eSJiri Olsa if (err) { 87699e7138eSJiri Olsa err->idx = term->err_val; 87799e7138eSJiri Olsa err->str = strdup("no value assigned for term"); 87899e7138eSJiri Olsa } 87999e7138eSJiri Olsa return -EINVAL; 88099e7138eSJiri Olsa } 88199e7138eSJiri Olsa 882688d4dfcSCody P Schafer val = term->val.num; 88399e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 884688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 885bb963e16SNamhyung Kim if (verbose > 0) { 886688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 887688d4dfcSCody P Schafer term->config, term->val.str); 888e64b020bSJiri Olsa } 889e64b020bSJiri Olsa if (err) { 890e64b020bSJiri Olsa err->idx = term->err_val; 891e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 892e64b020bSJiri Olsa } 893688d4dfcSCody P Schafer return -EINVAL; 894688d4dfcSCody P Schafer } 895688d4dfcSCody P Schafer 896688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 897688d4dfcSCody P Schafer return -EINVAL; 898688d4dfcSCody P Schafer } else 899688d4dfcSCody P Schafer return -EINVAL; 900688d4dfcSCody P Schafer 9010efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 9020efe6b67SAdrian Hunter if (val > max_val) { 9030efe6b67SAdrian Hunter if (err) { 9040efe6b67SAdrian Hunter err->idx = term->err_val; 9050efe6b67SAdrian Hunter if (asprintf(&err->str, 9060efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 9070efe6b67SAdrian Hunter (unsigned long long)max_val) < 0) 9080efe6b67SAdrian Hunter err->str = strdup("value too big for format"); 9090efe6b67SAdrian Hunter return -EINVAL; 9100efe6b67SAdrian Hunter } 9110efe6b67SAdrian Hunter /* 9120efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 9130efe6b67SAdrian Hunter * silently truncated. 9140efe6b67SAdrian Hunter */ 9150efe6b67SAdrian Hunter } 9160efe6b67SAdrian Hunter 917688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 918cd82a32eSJiri Olsa return 0; 919cd82a32eSJiri Olsa } 920cd82a32eSJiri Olsa 921cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 922cff7f956SJiri Olsa struct perf_event_attr *attr, 923dc0a6202SAdrian Hunter struct list_head *head_terms, 924e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 925cd82a32eSJiri Olsa { 9266cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 927cd82a32eSJiri Olsa 928688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 929e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 930e64b020bSJiri Olsa zero, err)) 931cd82a32eSJiri Olsa return -EINVAL; 932688d4dfcSCody P Schafer } 933cd82a32eSJiri Olsa 934cd82a32eSJiri Olsa return 0; 935cd82a32eSJiri Olsa } 936cd82a32eSJiri Olsa 937cd82a32eSJiri Olsa /* 938cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 939cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 940cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 941cd82a32eSJiri Olsa */ 942cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 943e64b020bSJiri Olsa struct list_head *head_terms, 944e64b020bSJiri Olsa struct parse_events_error *err) 945cd82a32eSJiri Olsa { 946dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 947dc0a6202SAdrian Hunter 948cd82a32eSJiri Olsa attr->type = pmu->type; 949e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 950e64b020bSJiri Olsa zero, err); 951cd82a32eSJiri Olsa } 952cd82a32eSJiri Olsa 9535c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 9546cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 955a6146d50SZheng Yan { 9565c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 957a6146d50SZheng Yan char *name; 958a6146d50SZheng Yan 959a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 960a6146d50SZheng Yan return NULL; 961a6146d50SZheng Yan 962a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 963a6146d50SZheng Yan if (term->val.num != 1) 964a6146d50SZheng Yan return NULL; 965a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 966a6146d50SZheng Yan return NULL; 967a6146d50SZheng Yan name = term->config; 968a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 969a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 970a6146d50SZheng Yan return NULL; 971a6146d50SZheng Yan name = term->val.str; 972a6146d50SZheng Yan } else { 973a6146d50SZheng Yan return NULL; 974a6146d50SZheng Yan } 975a6146d50SZheng Yan 976a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 977a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 978a6146d50SZheng Yan return alias; 979a6146d50SZheng Yan } 980a6146d50SZheng Yan return NULL; 981a6146d50SZheng Yan } 982a6146d50SZheng Yan 983410136f5SStephane Eranian 9841d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 9851d9e446bSJiri Olsa struct perf_pmu_info *info) 986410136f5SStephane Eranian { 987410136f5SStephane Eranian /* 988410136f5SStephane Eranian * Only one term in event definition can 9891d9e446bSJiri Olsa * define unit, scale and snapshot, fail 9901d9e446bSJiri Olsa * if there's more than one. 991410136f5SStephane Eranian */ 992b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 9931d9e446bSJiri Olsa (info->scale && alias->scale) || 9941d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 995410136f5SStephane Eranian return -EINVAL; 996410136f5SStephane Eranian 997b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 9981d9e446bSJiri Olsa info->unit = alias->unit; 999410136f5SStephane Eranian 1000410136f5SStephane Eranian if (alias->scale) 10011d9e446bSJiri Olsa info->scale = alias->scale; 10021d9e446bSJiri Olsa 10031d9e446bSJiri Olsa if (alias->snapshot) 10041d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1005410136f5SStephane Eranian 1006410136f5SStephane Eranian return 0; 1007410136f5SStephane Eranian } 1008410136f5SStephane Eranian 1009a6146d50SZheng Yan /* 1010a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1011a6146d50SZheng Yan * defined for the alias 1012a6146d50SZheng Yan */ 1013410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 101446441bdcSMatt Fleming struct perf_pmu_info *info) 1015a6146d50SZheng Yan { 10166cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 10175c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1018a6146d50SZheng Yan int ret; 1019a6146d50SZheng Yan 1020044330c1SMatt Fleming info->per_pkg = false; 1021044330c1SMatt Fleming 10228a398897SStephane Eranian /* 10238a398897SStephane Eranian * Mark unit and scale as not set 10248a398897SStephane Eranian * (different from default values, see below) 10258a398897SStephane Eranian */ 102646441bdcSMatt Fleming info->unit = NULL; 102746441bdcSMatt Fleming info->scale = 0.0; 10281d9e446bSJiri Olsa info->snapshot = false; 102937932c18SAndi Kleen info->metric_expr = NULL; 103096284814SAndi Kleen info->metric_name = NULL; 1031410136f5SStephane Eranian 1032a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1033a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1034a6146d50SZheng Yan if (!alias) 1035a6146d50SZheng Yan continue; 1036a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1037a6146d50SZheng Yan if (ret) 1038a6146d50SZheng Yan return ret; 1039410136f5SStephane Eranian 10401d9e446bSJiri Olsa ret = check_info_data(alias, info); 1041410136f5SStephane Eranian if (ret) 1042410136f5SStephane Eranian return ret; 1043410136f5SStephane Eranian 1044044330c1SMatt Fleming if (alias->per_pkg) 1045044330c1SMatt Fleming info->per_pkg = true; 104637932c18SAndi Kleen info->metric_expr = alias->metric_expr; 104796284814SAndi Kleen info->metric_name = alias->metric_name; 1048044330c1SMatt Fleming 1049a6146d50SZheng Yan list_del(&term->list); 1050a6146d50SZheng Yan free(term); 1051a6146d50SZheng Yan } 10528a398897SStephane Eranian 10538a398897SStephane Eranian /* 10548a398897SStephane Eranian * if no unit or scale foundin aliases, then 10558a398897SStephane Eranian * set defaults as for evsel 10568a398897SStephane Eranian * unit cannot left to NULL 10578a398897SStephane Eranian */ 105846441bdcSMatt Fleming if (info->unit == NULL) 105946441bdcSMatt Fleming info->unit = ""; 10608a398897SStephane Eranian 106146441bdcSMatt Fleming if (info->scale == 0.0) 106246441bdcSMatt Fleming info->scale = 1.0; 10638a398897SStephane Eranian 1064a6146d50SZheng Yan return 0; 1065a6146d50SZheng Yan } 1066a6146d50SZheng Yan 1067cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1068cd82a32eSJiri Olsa int config, unsigned long *bits) 1069cd82a32eSJiri Olsa { 10705c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1071cd82a32eSJiri Olsa 1072cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1073cd82a32eSJiri Olsa if (!format) 1074cd82a32eSJiri Olsa return -ENOMEM; 1075cd82a32eSJiri Olsa 1076cd82a32eSJiri Olsa format->name = strdup(name); 1077cd82a32eSJiri Olsa format->value = config; 1078cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1079cd82a32eSJiri Olsa 1080cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1081cd82a32eSJiri Olsa return 0; 1082cd82a32eSJiri Olsa } 1083cd82a32eSJiri Olsa 1084cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1085cd82a32eSJiri Olsa { 1086cd82a32eSJiri Olsa long b; 1087cd82a32eSJiri Olsa 1088cd82a32eSJiri Olsa if (!to) 1089cd82a32eSJiri Olsa to = from; 1090cd82a32eSJiri Olsa 109115268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1092cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1093cd82a32eSJiri Olsa set_bit(b, bits); 1094cd82a32eSJiri Olsa } 1095dc098b35SAndi Kleen 1096aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1097aaea3617SCody P Schafer { 1098aaea3617SCody P Schafer if (b > a) 1099aaea3617SCody P Schafer return 0; 1100aaea3617SCody P Schafer return a - b; 1101aaea3617SCody P Schafer } 1102aaea3617SCody P Schafer 1103dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1104dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1105dc098b35SAndi Kleen { 1106aaea3617SCody P Schafer struct parse_events_term *term; 1107aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1108aaea3617SCody P Schafer 1109aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1110aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1111aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1112aaea3617SCody P Schafer ",%s=%s", term->config, 1113aaea3617SCody P Schafer term->val.str); 1114aaea3617SCody P Schafer } 1115aaea3617SCody P Schafer 1116aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1117aaea3617SCody P Schafer buf[used] = '/'; 1118aaea3617SCody P Schafer used++; 1119aaea3617SCody P Schafer } 1120aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1121aaea3617SCody P Schafer buf[used] = '\0'; 1122aaea3617SCody P Schafer used++; 1123aaea3617SCody P Schafer } else 1124aaea3617SCody P Schafer buf[len - 1] = '\0'; 1125aaea3617SCody P Schafer 1126dc098b35SAndi Kleen return buf; 1127dc098b35SAndi Kleen } 1128dc098b35SAndi Kleen 1129dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1130dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1131dc098b35SAndi Kleen { 1132dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1133dc098b35SAndi Kleen return buf; 1134dc098b35SAndi Kleen } 1135dc098b35SAndi Kleen 1136dd5f1036SAndi Kleen struct sevent { 113708e60ed1SAndi Kleen char *name; 113808e60ed1SAndi Kleen char *desc; 1139dd5f1036SAndi Kleen char *topic; 1140f2361024SAndi Kleen char *str; 1141f2361024SAndi Kleen char *pmu; 11427f372a63SAndi Kleen char *metric_expr; 114396284814SAndi Kleen char *metric_name; 114408e60ed1SAndi Kleen }; 114508e60ed1SAndi Kleen 1146dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1147dc098b35SAndi Kleen { 1148dd5f1036SAndi Kleen const struct sevent *as = a; 1149dd5f1036SAndi Kleen const struct sevent *bs = b; 115008e60ed1SAndi Kleen 115108e60ed1SAndi Kleen /* Put extra events last */ 115208e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 115308e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1154dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1155dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1156dd5f1036SAndi Kleen 1157dd5f1036SAndi Kleen if (n) 1158dd5f1036SAndi Kleen return n; 1159dd5f1036SAndi Kleen } 116008e60ed1SAndi Kleen return strcmp(as->name, bs->name); 116108e60ed1SAndi Kleen } 116208e60ed1SAndi Kleen 116308e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 116408e60ed1SAndi Kleen { 116508e60ed1SAndi Kleen int column = start; 116608e60ed1SAndi Kleen int n; 116708e60ed1SAndi Kleen 116808e60ed1SAndi Kleen while (*s) { 116908e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 117008e60ed1SAndi Kleen 117108e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 117208e60ed1SAndi Kleen printf("\n%*s", start, ""); 117308e60ed1SAndi Kleen column = start + corr; 117408e60ed1SAndi Kleen } 117508e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 117608e60ed1SAndi Kleen if (n <= 0) 117708e60ed1SAndi Kleen break; 117808e60ed1SAndi Kleen s += wlen; 117908e60ed1SAndi Kleen column += n; 1180aa4beb10STaeung Song s = ltrim(s); 118108e60ed1SAndi Kleen } 1182dc098b35SAndi Kleen } 1183dc098b35SAndi Kleen 1184c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1185bf874fcfSAndi Kleen bool long_desc, bool details_flag) 1186dc098b35SAndi Kleen { 1187dc098b35SAndi Kleen struct perf_pmu *pmu; 1188dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1189dc098b35SAndi Kleen char buf[1024]; 1190dc098b35SAndi Kleen int printed = 0; 1191dc098b35SAndi Kleen int len, j; 1192dd5f1036SAndi Kleen struct sevent *aliases; 119308e60ed1SAndi Kleen int numdesc = 0; 119461eb2eb4SAndi Kleen int columns = pager_get_columns(); 1195dd5f1036SAndi Kleen char *topic = NULL; 1196dc098b35SAndi Kleen 1197dc098b35SAndi Kleen pmu = NULL; 1198dc098b35SAndi Kleen len = 0; 119942634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1200dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1201dc098b35SAndi Kleen len++; 120242634bc7SAdrian Hunter if (pmu->selectable) 120342634bc7SAdrian Hunter len++; 120442634bc7SAdrian Hunter } 1205dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1206dc098b35SAndi Kleen if (!aliases) 12077e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1208dc098b35SAndi Kleen pmu = NULL; 1209dc098b35SAndi Kleen j = 0; 121042634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1211dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 121208e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 121308e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1214dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1215dc098b35SAndi Kleen 1216dc098b35SAndi Kleen if (event_glob != NULL && 121738d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 121838d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 121967bdc35fSAndi Kleen event_glob)) || 122067bdc35fSAndi Kleen (alias->topic && 122167bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1222dc098b35SAndi Kleen continue; 12237e4772dcSArnaldo Carvalho de Melo 122408e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 12257e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 12267e4772dcSArnaldo Carvalho de Melo 122708e60ed1SAndi Kleen aliases[j].name = name; 122808e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 122908e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 123008e60ed1SAndi Kleen sizeof(buf), 123108e60ed1SAndi Kleen pmu, alias); 123208e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 123308e60ed1SAndi Kleen if (!aliases[j].name) 12347e4772dcSArnaldo Carvalho de Melo goto out_enomem; 123508e60ed1SAndi Kleen 1236c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1237c8d6828aSSukadev Bhattiprolu alias->desc; 1238dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1239f2361024SAndi Kleen aliases[j].str = alias->str; 1240f2361024SAndi Kleen aliases[j].pmu = pmu->name; 12417f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 124296284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1243dc098b35SAndi Kleen j++; 1244dc098b35SAndi Kleen } 1245fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1246fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 12477e4772dcSArnaldo Carvalho de Melo char *s; 12487e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 12497e4772dcSArnaldo Carvalho de Melo goto out_enomem; 125008e60ed1SAndi Kleen aliases[j].name = s; 125142634bc7SAdrian Hunter j++; 125242634bc7SAdrian Hunter } 125342634bc7SAdrian Hunter } 1254dc098b35SAndi Kleen len = j; 1255dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1256dc098b35SAndi Kleen for (j = 0; j < len; j++) { 125715b22ed3SAndi Kleen /* Skip duplicates */ 125815b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 125915b22ed3SAndi Kleen continue; 1260dc098b35SAndi Kleen if (name_only) { 126108e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1262dc098b35SAndi Kleen continue; 1263dc098b35SAndi Kleen } 12641c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 126508e60ed1SAndi Kleen if (numdesc++ == 0) 126608e60ed1SAndi Kleen printf("\n"); 1267dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1268dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1269dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1270dd5f1036SAndi Kleen aliases[j].topic); 1271dd5f1036SAndi Kleen topic = aliases[j].topic; 1272dd5f1036SAndi Kleen } 127308e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 127408e60ed1SAndi Kleen printf("%*s", 8, "["); 127508e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 127608e60ed1SAndi Kleen printf("]\n"); 1277bf874fcfSAndi Kleen if (details_flag) { 12787f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 127996284814SAndi Kleen if (aliases[j].metric_name) 128096284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 12817f372a63SAndi Kleen if (aliases[j].metric_expr) 12827f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 12837f372a63SAndi Kleen putchar('\n'); 12847f372a63SAndi Kleen } 128508e60ed1SAndi Kleen } else 128608e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1287dc098b35SAndi Kleen printed++; 1288dc098b35SAndi Kleen } 1289dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1290dc098b35SAndi Kleen printf("\n"); 12917e4772dcSArnaldo Carvalho de Melo out_free: 12927e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 129308e60ed1SAndi Kleen zfree(&aliases[j].name); 12947e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 12957e4772dcSArnaldo Carvalho de Melo return; 12967e4772dcSArnaldo Carvalho de Melo 12977e4772dcSArnaldo Carvalho de Melo out_enomem: 12987e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 12997e4772dcSArnaldo Carvalho de Melo if (aliases) 13007e4772dcSArnaldo Carvalho de Melo goto out_free; 1301dc098b35SAndi Kleen } 13024cabc3d1SAndi Kleen 13034cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 13044cabc3d1SAndi Kleen { 13054cabc3d1SAndi Kleen struct perf_pmu *pmu; 13064cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 13074cabc3d1SAndi Kleen 13084cabc3d1SAndi Kleen pmu = NULL; 13094cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 13104cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 13114cabc3d1SAndi Kleen continue; 13124cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 13134cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 13144cabc3d1SAndi Kleen return true; 13154cabc3d1SAndi Kleen } 13164cabc3d1SAndi Kleen return false; 13174cabc3d1SAndi Kleen } 13187d4bdab5SAdrian Hunter 13197d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 13207d4bdab5SAdrian Hunter { 13217d4bdab5SAdrian Hunter struct stat st; 13227d4bdab5SAdrian Hunter char path[PATH_MAX]; 13237d4bdab5SAdrian Hunter const char *sysfs; 13247d4bdab5SAdrian Hunter 13257d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 13267d4bdab5SAdrian Hunter if (!sysfs) 13277d4bdab5SAdrian Hunter return NULL; 13287d4bdab5SAdrian Hunter 13297d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 13307d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 13317d4bdab5SAdrian Hunter 13327d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 13337d4bdab5SAdrian Hunter return NULL; 13347d4bdab5SAdrian Hunter 13357d4bdab5SAdrian Hunter return fopen(path, "r"); 13367d4bdab5SAdrian Hunter } 13377d4bdab5SAdrian Hunter 13387d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 13397d4bdab5SAdrian Hunter ...) 13407d4bdab5SAdrian Hunter { 13417d4bdab5SAdrian Hunter va_list args; 13427d4bdab5SAdrian Hunter FILE *file; 13437d4bdab5SAdrian Hunter int ret = EOF; 13447d4bdab5SAdrian Hunter 13457d4bdab5SAdrian Hunter va_start(args, fmt); 13467d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 13477d4bdab5SAdrian Hunter if (file) { 13487d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 13497d4bdab5SAdrian Hunter fclose(file); 13507d4bdab5SAdrian Hunter } 13517d4bdab5SAdrian Hunter va_end(args); 13527d4bdab5SAdrian Hunter return ret; 13537d4bdab5SAdrian Hunter } 1354