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 3250a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 3350a9667cSRobert Richter 34cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 35cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 36cd82a32eSJiri Olsa 37cd82a32eSJiri Olsa static LIST_HEAD(pmus); 38cd82a32eSJiri Olsa 39cd82a32eSJiri Olsa /* 40cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 41cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 42cd82a32eSJiri Olsa */ 43cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 44cd82a32eSJiri Olsa { 45cd82a32eSJiri Olsa struct dirent *evt_ent; 46cd82a32eSJiri Olsa DIR *format_dir; 47cd82a32eSJiri Olsa int ret = 0; 48cd82a32eSJiri Olsa 49cd82a32eSJiri Olsa format_dir = opendir(dir); 50cd82a32eSJiri Olsa if (!format_dir) 51cd82a32eSJiri Olsa return -EINVAL; 52cd82a32eSJiri Olsa 53cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 54cd82a32eSJiri Olsa char path[PATH_MAX]; 55cd82a32eSJiri Olsa char *name = evt_ent->d_name; 56cd82a32eSJiri Olsa FILE *file; 57cd82a32eSJiri Olsa 58cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 59cd82a32eSJiri Olsa continue; 60cd82a32eSJiri Olsa 61cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 62cd82a32eSJiri Olsa 63cd82a32eSJiri Olsa ret = -EINVAL; 64cd82a32eSJiri Olsa file = fopen(path, "r"); 65cd82a32eSJiri Olsa if (!file) 66cd82a32eSJiri Olsa break; 67cd82a32eSJiri Olsa 68cd82a32eSJiri Olsa perf_pmu_in = file; 69cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 70cd82a32eSJiri Olsa fclose(file); 71cd82a32eSJiri Olsa } 72cd82a32eSJiri Olsa 73cd82a32eSJiri Olsa closedir(format_dir); 74cd82a32eSJiri Olsa return ret; 75cd82a32eSJiri Olsa } 76cd82a32eSJiri Olsa 77cd82a32eSJiri Olsa /* 78cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 79cd82a32eSJiri Olsa * located at: 80cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 81cd82a32eSJiri Olsa */ 82b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 83cd82a32eSJiri Olsa { 84cd82a32eSJiri Olsa struct stat st; 85cd82a32eSJiri Olsa char path[PATH_MAX]; 86cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 87cd82a32eSJiri Olsa 88cd82a32eSJiri Olsa if (!sysfs) 89cd82a32eSJiri Olsa return -1; 90cd82a32eSJiri Olsa 91cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9250a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 93cd82a32eSJiri Olsa 94cd82a32eSJiri Olsa if (stat(path, &st) < 0) 959bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 96cd82a32eSJiri Olsa 97cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 98cd82a32eSJiri Olsa return -1; 99cd82a32eSJiri Olsa 100cd82a32eSJiri Olsa return 0; 101cd82a32eSJiri Olsa } 102cd82a32eSJiri Olsa 103d02fc6bcSAndi Kleen static int convert_scale(const char *scale, char **end, double *sval) 104d02fc6bcSAndi Kleen { 105d02fc6bcSAndi Kleen char *lc; 106d02fc6bcSAndi Kleen int ret = 0; 107d02fc6bcSAndi Kleen 108d02fc6bcSAndi Kleen /* 109d02fc6bcSAndi Kleen * save current locale 110d02fc6bcSAndi Kleen */ 111d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 112d02fc6bcSAndi Kleen 113d02fc6bcSAndi Kleen /* 114d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 115d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 116d02fc6bcSAndi Kleen * call below. 117d02fc6bcSAndi Kleen */ 118d02fc6bcSAndi Kleen lc = strdup(lc); 119d02fc6bcSAndi Kleen if (!lc) { 120d02fc6bcSAndi Kleen ret = -ENOMEM; 121d02fc6bcSAndi Kleen goto out; 122d02fc6bcSAndi Kleen } 123d02fc6bcSAndi Kleen 124d02fc6bcSAndi Kleen /* 125d02fc6bcSAndi Kleen * force to C locale to ensure kernel 126d02fc6bcSAndi Kleen * scale string is converted correctly. 127d02fc6bcSAndi Kleen * kernel uses default C locale. 128d02fc6bcSAndi Kleen */ 129d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 130d02fc6bcSAndi Kleen 131d02fc6bcSAndi Kleen *sval = strtod(scale, end); 132d02fc6bcSAndi Kleen 133d02fc6bcSAndi Kleen out: 134d02fc6bcSAndi Kleen /* restore locale */ 135d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 136d02fc6bcSAndi Kleen free(lc); 137d02fc6bcSAndi Kleen return ret; 138d02fc6bcSAndi Kleen } 139d02fc6bcSAndi Kleen 140410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 141410136f5SStephane Eranian { 142410136f5SStephane Eranian struct stat st; 143410136f5SStephane Eranian ssize_t sret; 144410136f5SStephane Eranian char scale[128]; 145410136f5SStephane Eranian int fd, ret = -1; 146410136f5SStephane Eranian char path[PATH_MAX]; 147410136f5SStephane Eranian 148410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 149410136f5SStephane Eranian 150410136f5SStephane Eranian fd = open(path, O_RDONLY); 151410136f5SStephane Eranian if (fd == -1) 152410136f5SStephane Eranian return -1; 153410136f5SStephane Eranian 154410136f5SStephane Eranian if (fstat(fd, &st) < 0) 155410136f5SStephane Eranian goto error; 156410136f5SStephane Eranian 157410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 158410136f5SStephane Eranian if (sret < 0) 159410136f5SStephane Eranian goto error; 160410136f5SStephane Eranian 1619ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1629ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1639ecae065SMadhavan Srinivasan else 164410136f5SStephane Eranian scale[sret] = '\0'; 1659ecae065SMadhavan Srinivasan 166d02fc6bcSAndi Kleen ret = convert_scale(scale, NULL, &alias->scale); 167410136f5SStephane Eranian error: 168410136f5SStephane Eranian close(fd); 169410136f5SStephane Eranian return ret; 170410136f5SStephane Eranian } 171410136f5SStephane Eranian 172410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 173410136f5SStephane Eranian { 174410136f5SStephane Eranian char path[PATH_MAX]; 175410136f5SStephane Eranian ssize_t sret; 176410136f5SStephane Eranian int fd; 177410136f5SStephane Eranian 178410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 179410136f5SStephane Eranian 180410136f5SStephane Eranian fd = open(path, O_RDONLY); 181410136f5SStephane Eranian if (fd == -1) 182410136f5SStephane Eranian return -1; 183410136f5SStephane Eranian 184410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 185410136f5SStephane Eranian if (sret < 0) 186410136f5SStephane Eranian goto error; 187410136f5SStephane Eranian 188410136f5SStephane Eranian close(fd); 189410136f5SStephane Eranian 1909ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1919ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1929ecae065SMadhavan Srinivasan else 193410136f5SStephane Eranian alias->unit[sret] = '\0'; 194410136f5SStephane Eranian 195410136f5SStephane Eranian return 0; 196410136f5SStephane Eranian error: 197410136f5SStephane Eranian close(fd); 198410136f5SStephane Eranian alias->unit[0] = '\0'; 199410136f5SStephane Eranian return -1; 200410136f5SStephane Eranian } 201410136f5SStephane Eranian 202044330c1SMatt Fleming static int 203044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 204044330c1SMatt Fleming { 205044330c1SMatt Fleming char path[PATH_MAX]; 206044330c1SMatt Fleming int fd; 207044330c1SMatt Fleming 208044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 209044330c1SMatt Fleming 210044330c1SMatt Fleming fd = open(path, O_RDONLY); 211044330c1SMatt Fleming if (fd == -1) 212044330c1SMatt Fleming return -1; 213044330c1SMatt Fleming 214044330c1SMatt Fleming close(fd); 215044330c1SMatt Fleming 216044330c1SMatt Fleming alias->per_pkg = true; 217044330c1SMatt Fleming return 0; 218044330c1SMatt Fleming } 219044330c1SMatt Fleming 2201d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2211d9e446bSJiri Olsa char *dir, char *name) 2221d9e446bSJiri Olsa { 2231d9e446bSJiri Olsa char path[PATH_MAX]; 2241d9e446bSJiri Olsa int fd; 2251d9e446bSJiri Olsa 2261d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2271d9e446bSJiri Olsa 2281d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2291d9e446bSJiri Olsa if (fd == -1) 2301d9e446bSJiri Olsa return -1; 2311d9e446bSJiri Olsa 2321d9e446bSJiri Olsa alias->snapshot = true; 2331d9e446bSJiri Olsa close(fd); 2341d9e446bSJiri Olsa return 0; 2351d9e446bSJiri Olsa } 2361d9e446bSJiri Olsa 23770c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 238fedb2b51SAndi Kleen char *desc, char *val, 239fedb2b51SAndi Kleen char *long_desc, char *topic, 24000636c3bSAndi Kleen char *unit, char *perpkg, 24196284814SAndi Kleen char *metric_expr, 24296284814SAndi Kleen char *metric_name) 243a6146d50SZheng Yan { 2445c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 245a6146d50SZheng Yan int ret; 246fedb2b51SAndi Kleen int num; 247a6146d50SZheng Yan 248a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 249a6146d50SZheng Yan if (!alias) 250a6146d50SZheng Yan return -ENOMEM; 251a6146d50SZheng Yan 252a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 253410136f5SStephane Eranian alias->scale = 1.0; 254410136f5SStephane Eranian alias->unit[0] = '\0'; 255044330c1SMatt Fleming alias->per_pkg = false; 25684530920SStephane Eranian alias->snapshot = false; 257410136f5SStephane Eranian 25870c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 259a6146d50SZheng Yan if (ret) { 26070c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 261a6146d50SZheng Yan free(alias); 262a6146d50SZheng Yan return ret; 263a6146d50SZheng Yan } 264a6146d50SZheng Yan 265a6146d50SZheng Yan alias->name = strdup(name); 26670c646e0SSukadev Bhattiprolu if (dir) { 267410136f5SStephane Eranian /* 268410136f5SStephane Eranian * load unit name and scale if available 269410136f5SStephane Eranian */ 270410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 271410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 272044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2731d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 27470c646e0SSukadev Bhattiprolu } 275410136f5SStephane Eranian 27600636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 27796284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 27808e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 279c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 280c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 281dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 282fedb2b51SAndi Kleen if (unit) { 283fedb2b51SAndi Kleen if (convert_scale(unit, &unit, &alias->scale) < 0) 284fedb2b51SAndi Kleen return -1; 285fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 286fedb2b51SAndi Kleen } 287fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 288f2361024SAndi Kleen alias->str = strdup(val); 289f2361024SAndi Kleen 290a6146d50SZheng Yan list_add_tail(&alias->list, list); 291410136f5SStephane Eranian 292a6146d50SZheng Yan return 0; 293a6146d50SZheng Yan } 294a6146d50SZheng Yan 29570c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 29670c646e0SSukadev Bhattiprolu { 29770c646e0SSukadev Bhattiprolu char buf[256]; 29870c646e0SSukadev Bhattiprolu int ret; 29970c646e0SSukadev Bhattiprolu 30070c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 30170c646e0SSukadev Bhattiprolu if (ret == 0) 30270c646e0SSukadev Bhattiprolu return -EINVAL; 30370c646e0SSukadev Bhattiprolu 30470c646e0SSukadev Bhattiprolu buf[ret] = 0; 30570c646e0SSukadev Bhattiprolu 306fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 30796284814SAndi Kleen NULL, NULL, NULL); 30870c646e0SSukadev Bhattiprolu } 30970c646e0SSukadev Bhattiprolu 31046441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 31146441bdcSMatt Fleming { 31246441bdcSMatt Fleming size_t len; 31346441bdcSMatt Fleming 31446441bdcSMatt Fleming len = strlen(name); 31546441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 31646441bdcSMatt Fleming return true; 31746441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 31846441bdcSMatt Fleming return true; 319044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 320044330c1SMatt Fleming return true; 3211d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 3221d9e446bSJiri Olsa return true; 32346441bdcSMatt Fleming 32446441bdcSMatt Fleming return false; 32546441bdcSMatt Fleming } 32646441bdcSMatt Fleming 327a6146d50SZheng Yan /* 328a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 329a6146d50SZheng Yan * specified in 'dir' parameter. 330a6146d50SZheng Yan */ 331a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 332a6146d50SZheng Yan { 333a6146d50SZheng Yan struct dirent *evt_ent; 334a6146d50SZheng Yan DIR *event_dir; 335a6146d50SZheng Yan 336a6146d50SZheng Yan event_dir = opendir(dir); 337a6146d50SZheng Yan if (!event_dir) 338a6146d50SZheng Yan return -EINVAL; 339a6146d50SZheng Yan 340940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 341a6146d50SZheng Yan char path[PATH_MAX]; 342a6146d50SZheng Yan char *name = evt_ent->d_name; 343a6146d50SZheng Yan FILE *file; 344a6146d50SZheng Yan 345a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 346a6146d50SZheng Yan continue; 347a6146d50SZheng Yan 348410136f5SStephane Eranian /* 34946441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 350410136f5SStephane Eranian */ 35146441bdcSMatt Fleming if (pmu_alias_info_file(name)) 352410136f5SStephane Eranian continue; 353410136f5SStephane Eranian 354a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 355a6146d50SZheng Yan 356a6146d50SZheng Yan file = fopen(path, "r"); 357940db6dcSAndi Kleen if (!file) { 358940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 359940db6dcSAndi Kleen continue; 360940db6dcSAndi Kleen } 361410136f5SStephane Eranian 362940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 363940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 364a6146d50SZheng Yan fclose(file); 365a6146d50SZheng Yan } 366a6146d50SZheng Yan 367a6146d50SZheng Yan closedir(event_dir); 368940db6dcSAndi Kleen return 0; 369a6146d50SZheng Yan } 370a6146d50SZheng Yan 371a6146d50SZheng Yan /* 372a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 373a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 374a6146d50SZheng Yan */ 375b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 376a6146d50SZheng Yan { 377a6146d50SZheng Yan struct stat st; 378a6146d50SZheng Yan char path[PATH_MAX]; 379cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 380a6146d50SZheng Yan 381a6146d50SZheng Yan if (!sysfs) 382a6146d50SZheng Yan return -1; 383a6146d50SZheng Yan 384a6146d50SZheng Yan snprintf(path, PATH_MAX, 385a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 386a6146d50SZheng Yan 387a6146d50SZheng Yan if (stat(path, &st) < 0) 3883fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 389a6146d50SZheng Yan 390a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 391a6146d50SZheng Yan return -1; 392a6146d50SZheng Yan 393a6146d50SZheng Yan return 0; 394a6146d50SZheng Yan } 395a6146d50SZheng Yan 3965c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 397a6146d50SZheng Yan struct list_head *terms) 398a6146d50SZheng Yan { 3997c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 400a6146d50SZheng Yan LIST_HEAD(list); 401a6146d50SZheng Yan int ret; 402a6146d50SZheng Yan 403a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 4047c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 405a6146d50SZheng Yan if (ret) { 406682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 407a6146d50SZheng Yan return ret; 408a6146d50SZheng Yan } 409c2f1ceadSAndi Kleen /* 410c2f1ceadSAndi Kleen * Weak terms don't override command line options, 411c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 412c2f1ceadSAndi Kleen */ 413c2f1ceadSAndi Kleen cloned->weak = true; 4147c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 415a6146d50SZheng Yan } 416a6146d50SZheng Yan list_splice(&list, terms); 417a6146d50SZheng Yan return 0; 418a6146d50SZheng Yan } 419a6146d50SZheng Yan 420cd82a32eSJiri Olsa /* 421cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 422cd82a32eSJiri Olsa * located at: 423cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 424cd82a32eSJiri Olsa */ 425b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 426cd82a32eSJiri Olsa { 427cd82a32eSJiri Olsa struct stat st; 428cd82a32eSJiri Olsa char path[PATH_MAX]; 429cd82a32eSJiri Olsa FILE *file; 430cd82a32eSJiri Olsa int ret = 0; 431cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 432cd82a32eSJiri Olsa 433cd82a32eSJiri Olsa if (!sysfs) 434cd82a32eSJiri Olsa return -1; 435cd82a32eSJiri Olsa 436cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 43750a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 438cd82a32eSJiri Olsa 439cd82a32eSJiri Olsa if (stat(path, &st) < 0) 440cd82a32eSJiri Olsa return -1; 441cd82a32eSJiri Olsa 442cd82a32eSJiri Olsa file = fopen(path, "r"); 443cd82a32eSJiri Olsa if (!file) 444cd82a32eSJiri Olsa return -EINVAL; 445cd82a32eSJiri Olsa 446cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 447cd82a32eSJiri Olsa ret = -1; 448cd82a32eSJiri Olsa 449cd82a32eSJiri Olsa fclose(file); 450cd82a32eSJiri Olsa return ret; 451cd82a32eSJiri Olsa } 452cd82a32eSJiri Olsa 45350a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 45450a9667cSRobert Richter static void pmu_read_sysfs(void) 45550a9667cSRobert Richter { 45650a9667cSRobert Richter char path[PATH_MAX]; 45750a9667cSRobert Richter DIR *dir; 45850a9667cSRobert Richter struct dirent *dent; 459cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 46050a9667cSRobert Richter 46150a9667cSRobert Richter if (!sysfs) 46250a9667cSRobert Richter return; 46350a9667cSRobert Richter 46450a9667cSRobert Richter snprintf(path, PATH_MAX, 46550a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 46650a9667cSRobert Richter 46750a9667cSRobert Richter dir = opendir(path); 46850a9667cSRobert Richter if (!dir) 46950a9667cSRobert Richter return; 47050a9667cSRobert Richter 47150a9667cSRobert Richter while ((dent = readdir(dir))) { 47250a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 47350a9667cSRobert Richter continue; 47450a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 47550a9667cSRobert Richter perf_pmu__find(dent->d_name); 47650a9667cSRobert Richter } 47750a9667cSRobert Richter 47850a9667cSRobert Richter closedir(dir); 47950a9667cSRobert Richter } 48050a9667cSRobert Richter 48166ec1191SMark Rutland static struct cpu_map *__pmu_cpumask(const char *path) 48266ec1191SMark Rutland { 48366ec1191SMark Rutland FILE *file; 48466ec1191SMark Rutland struct cpu_map *cpus; 48566ec1191SMark Rutland 48666ec1191SMark Rutland file = fopen(path, "r"); 48766ec1191SMark Rutland if (!file) 48866ec1191SMark Rutland return NULL; 48966ec1191SMark Rutland 49066ec1191SMark Rutland cpus = cpu_map__read(file); 49166ec1191SMark Rutland fclose(file); 49266ec1191SMark Rutland return cpus; 49366ec1191SMark Rutland } 49466ec1191SMark Rutland 49566ec1191SMark Rutland /* 49666ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 49766ec1191SMark Rutland * may have a "cpus" file. 49866ec1191SMark Rutland */ 49966ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 50066ec1191SMark Rutland #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 50166ec1191SMark Rutland 502b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 5037ae92e74SYan, Zheng { 5047ae92e74SYan, Zheng char path[PATH_MAX]; 5057ae92e74SYan, Zheng struct cpu_map *cpus; 506cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 5077e3fcffeSMark Rutland const char *templates[] = { 50866ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 50966ec1191SMark Rutland CPUS_TEMPLATE_CPU, 5107e3fcffeSMark Rutland NULL 5117e3fcffeSMark Rutland }; 5127e3fcffeSMark Rutland const char **template; 5137ae92e74SYan, Zheng 5147ae92e74SYan, Zheng if (!sysfs) 5157ae92e74SYan, Zheng return NULL; 5167ae92e74SYan, Zheng 5177e3fcffeSMark Rutland for (template = templates; *template; template++) { 5187e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 51966ec1191SMark Rutland cpus = __pmu_cpumask(path); 52066ec1191SMark Rutland if (cpus) 52166ec1191SMark Rutland return cpus; 5227e3fcffeSMark Rutland } 5237ae92e74SYan, Zheng 5247ae92e74SYan, Zheng return NULL; 52566ec1191SMark Rutland } 5267ae92e74SYan, Zheng 52766ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 52866ec1191SMark Rutland { 52966ec1191SMark Rutland char path[PATH_MAX]; 53066ec1191SMark Rutland struct cpu_map *cpus; 53166ec1191SMark Rutland const char *sysfs = sysfs__mountpoint(); 5327ae92e74SYan, Zheng 53366ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 53466ec1191SMark Rutland cpus = __pmu_cpumask(path); 53566ec1191SMark Rutland cpu_map__put(cpus); 53666ec1191SMark Rutland 53766ec1191SMark Rutland return !!cpus; 5387ae92e74SYan, Zheng } 5397ae92e74SYan, Zheng 540933f82ffSSukadev Bhattiprolu /* 54114b22ae0SGanapatrao Kulkarni * PMU CORE devices have different name other than cpu in sysfs on some 54214b22ae0SGanapatrao Kulkarni * platforms. looking for possible sysfs files to identify as core device. 54314b22ae0SGanapatrao Kulkarni */ 54414b22ae0SGanapatrao Kulkarni static int is_pmu_core(const char *name) 54514b22ae0SGanapatrao Kulkarni { 54614b22ae0SGanapatrao Kulkarni struct stat st; 54714b22ae0SGanapatrao Kulkarni char path[PATH_MAX]; 54814b22ae0SGanapatrao Kulkarni const char *sysfs = sysfs__mountpoint(); 54914b22ae0SGanapatrao Kulkarni 55014b22ae0SGanapatrao Kulkarni if (!sysfs) 55114b22ae0SGanapatrao Kulkarni return 0; 55214b22ae0SGanapatrao Kulkarni 55314b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (x86 and others) */ 55414b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu", sysfs); 55514b22ae0SGanapatrao Kulkarni if ((stat(path, &st) == 0) && 55614b22ae0SGanapatrao Kulkarni (strncmp(name, "cpu", strlen("cpu")) == 0)) 55714b22ae0SGanapatrao Kulkarni return 1; 55814b22ae0SGanapatrao Kulkarni 55914b22ae0SGanapatrao Kulkarni /* Look for cpu sysfs (specific to arm) */ 56014b22ae0SGanapatrao Kulkarni scnprintf(path, PATH_MAX, "%s/bus/event_source/devices/%s/cpus", 56114b22ae0SGanapatrao Kulkarni sysfs, name); 56214b22ae0SGanapatrao Kulkarni if (stat(path, &st) == 0) 56314b22ae0SGanapatrao Kulkarni return 1; 56414b22ae0SGanapatrao Kulkarni 56514b22ae0SGanapatrao Kulkarni return 0; 56614b22ae0SGanapatrao Kulkarni } 56714b22ae0SGanapatrao Kulkarni 56814b22ae0SGanapatrao Kulkarni /* 569933f82ffSSukadev Bhattiprolu * Return the CPU id as a raw string. 570933f82ffSSukadev Bhattiprolu * 571933f82ffSSukadev Bhattiprolu * Each architecture should provide a more precise id string that 572933f82ffSSukadev Bhattiprolu * can be use to match the architecture's "mapfile". 573933f82ffSSukadev Bhattiprolu */ 57454e32dc0SGanapatrao Kulkarni char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 575933f82ffSSukadev Bhattiprolu { 576933f82ffSSukadev Bhattiprolu return NULL; 577933f82ffSSukadev Bhattiprolu } 578933f82ffSSukadev Bhattiprolu 5794cb7d3ecSThomas Richter /* Return zero when the cpuid from the mapfile.csv matches the 5804cb7d3ecSThomas Richter * cpuid string generated on this platform. 5814cb7d3ecSThomas Richter * Otherwise return non-zero. 5824cb7d3ecSThomas Richter */ 5834cb7d3ecSThomas Richter int __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid) 5844cb7d3ecSThomas Richter { 5854cb7d3ecSThomas Richter regex_t re; 5864cb7d3ecSThomas Richter regmatch_t pmatch[1]; 5874cb7d3ecSThomas Richter int match; 5884cb7d3ecSThomas Richter 5894cb7d3ecSThomas Richter if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) { 5904cb7d3ecSThomas Richter /* Warn unable to generate match particular string. */ 5914cb7d3ecSThomas Richter pr_info("Invalid regular expression %s\n", mapcpuid); 5924cb7d3ecSThomas Richter return 1; 5934cb7d3ecSThomas Richter } 5944cb7d3ecSThomas Richter 5954cb7d3ecSThomas Richter match = !regexec(&re, cpuid, 1, pmatch, 0); 5964cb7d3ecSThomas Richter regfree(&re); 5974cb7d3ecSThomas Richter if (match) { 5984cb7d3ecSThomas Richter size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so); 5994cb7d3ecSThomas Richter 6004cb7d3ecSThomas Richter /* Verify the entire string matched. */ 6014cb7d3ecSThomas Richter if (match_len == strlen(cpuid)) 6024cb7d3ecSThomas Richter return 0; 6034cb7d3ecSThomas Richter } 6044cb7d3ecSThomas Richter return 1; 6054cb7d3ecSThomas Richter } 6064cb7d3ecSThomas Richter 60754e32dc0SGanapatrao Kulkarni static char *perf_pmu__getcpuid(struct perf_pmu *pmu) 608d77ade9fSAndi Kleen { 609d77ade9fSAndi Kleen char *cpuid; 610d77ade9fSAndi Kleen static bool printed; 611d77ade9fSAndi Kleen 612d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 613d77ade9fSAndi Kleen if (cpuid) 614d77ade9fSAndi Kleen cpuid = strdup(cpuid); 615d77ade9fSAndi Kleen if (!cpuid) 61654e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 617d77ade9fSAndi Kleen if (!cpuid) 618d77ade9fSAndi Kleen return NULL; 619d77ade9fSAndi Kleen 620d77ade9fSAndi Kleen if (!printed) { 621d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 622d77ade9fSAndi Kleen printed = true; 623d77ade9fSAndi Kleen } 624d77ade9fSAndi Kleen return cpuid; 625d77ade9fSAndi Kleen } 626d77ade9fSAndi Kleen 62754e32dc0SGanapatrao Kulkarni struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu) 628d77ade9fSAndi Kleen { 629d77ade9fSAndi Kleen struct pmu_events_map *map; 63054e32dc0SGanapatrao Kulkarni char *cpuid = perf_pmu__getcpuid(pmu); 631d77ade9fSAndi Kleen int i; 632d77ade9fSAndi Kleen 633de3d0f12SGanapatrao Kulkarni /* on some platforms which uses cpus map, cpuid can be NULL for 634de3d0f12SGanapatrao Kulkarni * PMUs other than CORE PMUs. 635de3d0f12SGanapatrao Kulkarni */ 636de3d0f12SGanapatrao Kulkarni if (!cpuid) 637de3d0f12SGanapatrao Kulkarni return NULL; 638de3d0f12SGanapatrao Kulkarni 639d77ade9fSAndi Kleen i = 0; 640d77ade9fSAndi Kleen for (;;) { 641d77ade9fSAndi Kleen map = &pmu_events_map[i++]; 642d77ade9fSAndi Kleen if (!map->table) { 643d77ade9fSAndi Kleen map = NULL; 644d77ade9fSAndi Kleen break; 645d77ade9fSAndi Kleen } 646d77ade9fSAndi Kleen 6474cb7d3ecSThomas Richter if (!strcmp_cpuid_str(map->cpuid, cpuid)) 648d77ade9fSAndi Kleen break; 649d77ade9fSAndi Kleen } 650d77ade9fSAndi Kleen free(cpuid); 651d77ade9fSAndi Kleen return map; 652d77ade9fSAndi Kleen } 653d77ade9fSAndi Kleen 654933f82ffSSukadev Bhattiprolu /* 655933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 656933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 657933f82ffSSukadev Bhattiprolu * as aliases. 658933f82ffSSukadev Bhattiprolu */ 65954e32dc0SGanapatrao Kulkarni static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 660933f82ffSSukadev Bhattiprolu { 661933f82ffSSukadev Bhattiprolu int i; 662933f82ffSSukadev Bhattiprolu struct pmu_events_map *map; 663933f82ffSSukadev Bhattiprolu struct pmu_event *pe; 66454e32dc0SGanapatrao Kulkarni const char *name = pmu->name; 665933f82ffSSukadev Bhattiprolu 66654e32dc0SGanapatrao Kulkarni map = perf_pmu__find_map(pmu); 667d77ade9fSAndi Kleen if (!map) 668933f82ffSSukadev Bhattiprolu return; 669933f82ffSSukadev Bhattiprolu 670933f82ffSSukadev Bhattiprolu /* 671933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 672933f82ffSSukadev Bhattiprolu */ 673933f82ffSSukadev Bhattiprolu i = 0; 674933f82ffSSukadev Bhattiprolu while (1) { 675fedb2b51SAndi Kleen 676933f82ffSSukadev Bhattiprolu pe = &map->table[i++]; 677b18f3e36SAndi Kleen if (!pe->name) { 678b18f3e36SAndi Kleen if (pe->metric_group || pe->metric_name) 679b18f3e36SAndi Kleen continue; 680933f82ffSSukadev Bhattiprolu break; 681b18f3e36SAndi Kleen } 682933f82ffSSukadev Bhattiprolu 68314b22ae0SGanapatrao Kulkarni if (!is_pmu_core(name)) { 68414b22ae0SGanapatrao Kulkarni /* check for uncore devices */ 68514b22ae0SGanapatrao Kulkarni if (pe->pmu == NULL) 686fedb2b51SAndi Kleen continue; 68714b22ae0SGanapatrao Kulkarni if (strncmp(pe->pmu, name, strlen(pe->pmu))) 68814b22ae0SGanapatrao Kulkarni continue; 68914b22ae0SGanapatrao Kulkarni } 690fedb2b51SAndi Kleen 691933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 692933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 693c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 694fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 69500636c3bSAndi Kleen (char *)pe->unit, (char *)pe->perpkg, 69696284814SAndi Kleen (char *)pe->metric_expr, 69796284814SAndi Kleen (char *)pe->metric_name); 698933f82ffSSukadev Bhattiprolu } 699933f82ffSSukadev Bhattiprolu } 700933f82ffSSukadev Bhattiprolu 701c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 702dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 703dc0a6202SAdrian Hunter { 704dc0a6202SAdrian Hunter return NULL; 705dc0a6202SAdrian Hunter } 706dc0a6202SAdrian Hunter 707b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 708cd82a32eSJiri Olsa { 709cd82a32eSJiri Olsa struct perf_pmu *pmu; 710cd82a32eSJiri Olsa LIST_HEAD(format); 711a6146d50SZheng Yan LIST_HEAD(aliases); 712cd82a32eSJiri Olsa __u32 type; 713cd82a32eSJiri Olsa 714cd82a32eSJiri Olsa /* 715cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 716cd82a32eSJiri Olsa * type value and format definitions. Load both right 717cd82a32eSJiri Olsa * now. 718cd82a32eSJiri Olsa */ 719cd82a32eSJiri Olsa if (pmu_format(name, &format)) 720cd82a32eSJiri Olsa return NULL; 721cd82a32eSJiri Olsa 72215b22ed3SAndi Kleen /* 72315b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 72415b22ed3SAndi Kleen */ 72515b22ed3SAndi Kleen if (pmu_type(name, &type)) 72615b22ed3SAndi Kleen return NULL; 72715b22ed3SAndi Kleen 7283fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 7293fded963SJiri Olsa return NULL; 7303fded963SJiri Olsa 731cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 732cd82a32eSJiri Olsa if (!pmu) 733cd82a32eSJiri Olsa return NULL; 734cd82a32eSJiri Olsa 7357ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 73654e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 73754e32dc0SGanapatrao Kulkarni pmu->type = type; 73866ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 73954e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 74066ec1191SMark Rutland 741cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 742a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 743cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 744a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 7459bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 746dc0a6202SAdrian Hunter 747dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 748dc0a6202SAdrian Hunter 749cd82a32eSJiri Olsa return pmu; 750cd82a32eSJiri Olsa } 751cd82a32eSJiri Olsa 752b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 753cd82a32eSJiri Olsa { 754cd82a32eSJiri Olsa struct perf_pmu *pmu; 755cd82a32eSJiri Olsa 756cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 757cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 758cd82a32eSJiri Olsa return pmu; 759cd82a32eSJiri Olsa 760cd82a32eSJiri Olsa return NULL; 761cd82a32eSJiri Olsa } 762cd82a32eSJiri Olsa 76350a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 76450a9667cSRobert Richter { 76550a9667cSRobert Richter /* 76650a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 76750a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 76850a9667cSRobert Richter */ 76950a9667cSRobert Richter if (!pmu) { 77050a9667cSRobert Richter pmu_read_sysfs(); 77150a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 77250a9667cSRobert Richter } 77350a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 77450a9667cSRobert Richter return pmu; 77550a9667cSRobert Richter return NULL; 77650a9667cSRobert Richter } 77750a9667cSRobert Richter 778b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 779cd82a32eSJiri Olsa { 780cd82a32eSJiri Olsa struct perf_pmu *pmu; 781cd82a32eSJiri Olsa 782cd82a32eSJiri Olsa /* 783cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 784cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 785cd82a32eSJiri Olsa * the pmu format definitions. 786cd82a32eSJiri Olsa */ 787cd82a32eSJiri Olsa pmu = pmu_find(name); 788cd82a32eSJiri Olsa if (pmu) 789cd82a32eSJiri Olsa return pmu; 790cd82a32eSJiri Olsa 791cd82a32eSJiri Olsa return pmu_lookup(name); 792cd82a32eSJiri Olsa } 793cd82a32eSJiri Olsa 7945c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 79509ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 796cd82a32eSJiri Olsa { 7975c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 798cd82a32eSJiri Olsa 799cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 800cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 801cd82a32eSJiri Olsa return format; 802cd82a32eSJiri Olsa 803cd82a32eSJiri Olsa return NULL; 804cd82a32eSJiri Olsa } 805cd82a32eSJiri Olsa 80609ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 80709ff6071SAdrian Hunter { 80809ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 80909ff6071SAdrian Hunter __u64 bits = 0; 81009ff6071SAdrian Hunter int fbit; 81109ff6071SAdrian Hunter 81209ff6071SAdrian Hunter if (!format) 81309ff6071SAdrian Hunter return 0; 81409ff6071SAdrian Hunter 81509ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 81609ff6071SAdrian Hunter bits |= 1ULL << fbit; 81709ff6071SAdrian Hunter 81809ff6071SAdrian Hunter return bits; 81909ff6071SAdrian Hunter } 82009ff6071SAdrian Hunter 821cd82a32eSJiri Olsa /* 822dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 823cd82a32eSJiri Olsa * and unformated value (value parameter). 824cd82a32eSJiri Olsa */ 825dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 826dc0a6202SAdrian Hunter bool zero) 827cd82a32eSJiri Olsa { 828cd82a32eSJiri Olsa unsigned long fbit, vbit; 829cd82a32eSJiri Olsa 830cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 831cd82a32eSJiri Olsa 832cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 833cd82a32eSJiri Olsa continue; 834cd82a32eSJiri Olsa 835dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 836dc0a6202SAdrian Hunter *v |= (1llu << fbit); 837dc0a6202SAdrian Hunter else if (zero) 838dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 839cd82a32eSJiri Olsa } 840cd82a32eSJiri Olsa } 841cd82a32eSJiri Olsa 8420efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 8430efe6b67SAdrian Hunter { 844ac0e2cd5SKan Liang __u64 w = 0; 845ac0e2cd5SKan Liang int fbit; 8460efe6b67SAdrian Hunter 847ac0e2cd5SKan Liang for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) 848ac0e2cd5SKan Liang w |= (1ULL << fbit); 849ac0e2cd5SKan Liang 850ac0e2cd5SKan Liang return w; 8510efe6b67SAdrian Hunter } 8520efe6b67SAdrian Hunter 853cd82a32eSJiri Olsa /* 854688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 855688d4dfcSCody P Schafer * in the remaining terms. 856688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 857688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 858688d4dfcSCody P Schafer * in a config string) later on in the term list. 859688d4dfcSCody P Schafer */ 860688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 861688d4dfcSCody P Schafer struct list_head *head_terms, 862688d4dfcSCody P Schafer __u64 *value) 863688d4dfcSCody P Schafer { 864688d4dfcSCody P Schafer struct parse_events_term *t; 865688d4dfcSCody P Schafer 866688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 867688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 868688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 869688d4dfcSCody P Schafer t->used = true; 870688d4dfcSCody P Schafer *value = t->val.num; 871688d4dfcSCody P Schafer return 0; 872688d4dfcSCody P Schafer } 873688d4dfcSCody P Schafer } 874688d4dfcSCody P Schafer } 875688d4dfcSCody P Schafer 876bb963e16SNamhyung Kim if (verbose > 0) 877688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 878688d4dfcSCody P Schafer 879688d4dfcSCody P Schafer return -1; 880688d4dfcSCody P Schafer } 881688d4dfcSCody P Schafer 882ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 883e64b020bSJiri Olsa { 884e64b020bSJiri Olsa struct perf_pmu_format *format; 88511db4e29SMasami Hiramatsu char *str = NULL; 88611db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 887e64b020bSJiri Olsa unsigned i = 0; 888e64b020bSJiri Olsa 889ffeb883eSHe Kuang if (!formats) 890e64b020bSJiri Olsa return NULL; 891e64b020bSJiri Olsa 892e64b020bSJiri Olsa /* sysfs exported terms */ 893ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 89411db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 89511db4e29SMasami Hiramatsu goto error; 896e64b020bSJiri Olsa 897ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 89811db4e29SMasami Hiramatsu error: 899ffeb883eSHe Kuang strbuf_release(&buf); 900e64b020bSJiri Olsa 901e64b020bSJiri Olsa return str; 902e64b020bSJiri Olsa } 903e64b020bSJiri Olsa 904688d4dfcSCody P Schafer /* 905cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 90688aca8d9SCody P Schafer * user input data - term parameter. 907cd82a32eSJiri Olsa */ 908cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 909cd82a32eSJiri Olsa struct perf_event_attr *attr, 910dc0a6202SAdrian Hunter struct parse_events_term *term, 911688d4dfcSCody P Schafer struct list_head *head_terms, 912e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 913cd82a32eSJiri Olsa { 9145c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 915cd82a32eSJiri Olsa __u64 *vp; 9160efe6b67SAdrian Hunter __u64 val, max_val; 917cd82a32eSJiri Olsa 918cd82a32eSJiri Olsa /* 919688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 920688d4dfcSCody P Schafer * skip it in normal eval. 921688d4dfcSCody P Schafer */ 922688d4dfcSCody P Schafer if (term->used) 923688d4dfcSCody P Schafer return 0; 924688d4dfcSCody P Schafer 925688d4dfcSCody P Schafer /* 926cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 927cd82a32eSJiri Olsa * to be done for them. 928cd82a32eSJiri Olsa */ 929cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 930cd82a32eSJiri Olsa return 0; 931cd82a32eSJiri Olsa 932cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 933688d4dfcSCody P Schafer if (!format) { 934bb963e16SNamhyung Kim if (verbose > 0) 935688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 936e64b020bSJiri Olsa if (err) { 937ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 938ffeb883eSHe Kuang 939e64b020bSJiri Olsa err->idx = term->err_term; 940e64b020bSJiri Olsa err->str = strdup("unknown term"); 941ffeb883eSHe Kuang err->help = parse_events_formats_error_string(pmu_term); 942ffeb883eSHe Kuang free(pmu_term); 943e64b020bSJiri Olsa } 944cd82a32eSJiri Olsa return -EINVAL; 945688d4dfcSCody P Schafer } 946cd82a32eSJiri Olsa 947cd82a32eSJiri Olsa switch (format->value) { 948cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 949cd82a32eSJiri Olsa vp = &attr->config; 950cd82a32eSJiri Olsa break; 951cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 952cd82a32eSJiri Olsa vp = &attr->config1; 953cd82a32eSJiri Olsa break; 954cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 955cd82a32eSJiri Olsa vp = &attr->config2; 956cd82a32eSJiri Olsa break; 957cd82a32eSJiri Olsa default: 958cd82a32eSJiri Olsa return -EINVAL; 959cd82a32eSJiri Olsa } 960cd82a32eSJiri Olsa 96116fa7e82SJiri Olsa /* 962688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 963688d4dfcSCody P Schafer * using event parameters. 96416fa7e82SJiri Olsa */ 96599e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 96699e7138eSJiri Olsa if (term->no_value && 96799e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 96899e7138eSJiri Olsa if (err) { 96999e7138eSJiri Olsa err->idx = term->err_val; 97099e7138eSJiri Olsa err->str = strdup("no value assigned for term"); 97199e7138eSJiri Olsa } 97299e7138eSJiri Olsa return -EINVAL; 97399e7138eSJiri Olsa } 97499e7138eSJiri Olsa 975688d4dfcSCody P Schafer val = term->val.num; 97699e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 977688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 978bb963e16SNamhyung Kim if (verbose > 0) { 979688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 980688d4dfcSCody P Schafer term->config, term->val.str); 981e64b020bSJiri Olsa } 982e64b020bSJiri Olsa if (err) { 983e64b020bSJiri Olsa err->idx = term->err_val; 984e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 985e64b020bSJiri Olsa } 986688d4dfcSCody P Schafer return -EINVAL; 987688d4dfcSCody P Schafer } 988688d4dfcSCody P Schafer 989688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 990688d4dfcSCody P Schafer return -EINVAL; 991688d4dfcSCody P Schafer } else 992688d4dfcSCody P Schafer return -EINVAL; 993688d4dfcSCody P Schafer 9940efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 9950efe6b67SAdrian Hunter if (val > max_val) { 9960efe6b67SAdrian Hunter if (err) { 9970efe6b67SAdrian Hunter err->idx = term->err_val; 9980efe6b67SAdrian Hunter if (asprintf(&err->str, 9990efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 10000efe6b67SAdrian Hunter (unsigned long long)max_val) < 0) 10010efe6b67SAdrian Hunter err->str = strdup("value too big for format"); 10020efe6b67SAdrian Hunter return -EINVAL; 10030efe6b67SAdrian Hunter } 10040efe6b67SAdrian Hunter /* 10050efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 10060efe6b67SAdrian Hunter * silently truncated. 10070efe6b67SAdrian Hunter */ 10080efe6b67SAdrian Hunter } 10090efe6b67SAdrian Hunter 1010688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 1011cd82a32eSJiri Olsa return 0; 1012cd82a32eSJiri Olsa } 1013cd82a32eSJiri Olsa 1014cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 1015cff7f956SJiri Olsa struct perf_event_attr *attr, 1016dc0a6202SAdrian Hunter struct list_head *head_terms, 1017e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 1018cd82a32eSJiri Olsa { 10196cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 1020cd82a32eSJiri Olsa 1021688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 1022e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 1023e64b020bSJiri Olsa zero, err)) 1024cd82a32eSJiri Olsa return -EINVAL; 1025688d4dfcSCody P Schafer } 1026cd82a32eSJiri Olsa 1027cd82a32eSJiri Olsa return 0; 1028cd82a32eSJiri Olsa } 1029cd82a32eSJiri Olsa 1030cd82a32eSJiri Olsa /* 1031cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 1032cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 1033cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 1034cd82a32eSJiri Olsa */ 1035cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 1036e64b020bSJiri Olsa struct list_head *head_terms, 1037e64b020bSJiri Olsa struct parse_events_error *err) 1038cd82a32eSJiri Olsa { 1039dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 1040dc0a6202SAdrian Hunter 1041cd82a32eSJiri Olsa attr->type = pmu->type; 1042e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 1043e64b020bSJiri Olsa zero, err); 1044cd82a32eSJiri Olsa } 1045cd82a32eSJiri Olsa 10465c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 10476cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 1048a6146d50SZheng Yan { 10495c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1050a6146d50SZheng Yan char *name; 1051a6146d50SZheng Yan 1052a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 1053a6146d50SZheng Yan return NULL; 1054a6146d50SZheng Yan 1055a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 1056a6146d50SZheng Yan if (term->val.num != 1) 1057a6146d50SZheng Yan return NULL; 1058a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 1059a6146d50SZheng Yan return NULL; 1060a6146d50SZheng Yan name = term->config; 1061a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 1062a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 1063a6146d50SZheng Yan return NULL; 1064a6146d50SZheng Yan name = term->val.str; 1065a6146d50SZheng Yan } else { 1066a6146d50SZheng Yan return NULL; 1067a6146d50SZheng Yan } 1068a6146d50SZheng Yan 1069a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1070a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1071a6146d50SZheng Yan return alias; 1072a6146d50SZheng Yan } 1073a6146d50SZheng Yan return NULL; 1074a6146d50SZheng Yan } 1075a6146d50SZheng Yan 1076410136f5SStephane Eranian 10771d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 10781d9e446bSJiri Olsa struct perf_pmu_info *info) 1079410136f5SStephane Eranian { 1080410136f5SStephane Eranian /* 1081410136f5SStephane Eranian * Only one term in event definition can 10821d9e446bSJiri Olsa * define unit, scale and snapshot, fail 10831d9e446bSJiri Olsa * if there's more than one. 1084410136f5SStephane Eranian */ 1085b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 10861d9e446bSJiri Olsa (info->scale && alias->scale) || 10871d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1088410136f5SStephane Eranian return -EINVAL; 1089410136f5SStephane Eranian 1090b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 10911d9e446bSJiri Olsa info->unit = alias->unit; 1092410136f5SStephane Eranian 1093410136f5SStephane Eranian if (alias->scale) 10941d9e446bSJiri Olsa info->scale = alias->scale; 10951d9e446bSJiri Olsa 10961d9e446bSJiri Olsa if (alias->snapshot) 10971d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1098410136f5SStephane Eranian 1099410136f5SStephane Eranian return 0; 1100410136f5SStephane Eranian } 1101410136f5SStephane Eranian 1102a6146d50SZheng Yan /* 1103a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1104a6146d50SZheng Yan * defined for the alias 1105a6146d50SZheng Yan */ 1106410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 110746441bdcSMatt Fleming struct perf_pmu_info *info) 1108a6146d50SZheng Yan { 11096cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 11105c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1111a6146d50SZheng Yan int ret; 1112a6146d50SZheng Yan 1113044330c1SMatt Fleming info->per_pkg = false; 1114044330c1SMatt Fleming 11158a398897SStephane Eranian /* 11168a398897SStephane Eranian * Mark unit and scale as not set 11178a398897SStephane Eranian * (different from default values, see below) 11188a398897SStephane Eranian */ 111946441bdcSMatt Fleming info->unit = NULL; 112046441bdcSMatt Fleming info->scale = 0.0; 11211d9e446bSJiri Olsa info->snapshot = false; 112237932c18SAndi Kleen info->metric_expr = NULL; 112396284814SAndi Kleen info->metric_name = NULL; 1124410136f5SStephane Eranian 1125a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1126a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1127a6146d50SZheng Yan if (!alias) 1128a6146d50SZheng Yan continue; 1129a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1130a6146d50SZheng Yan if (ret) 1131a6146d50SZheng Yan return ret; 1132410136f5SStephane Eranian 11331d9e446bSJiri Olsa ret = check_info_data(alias, info); 1134410136f5SStephane Eranian if (ret) 1135410136f5SStephane Eranian return ret; 1136410136f5SStephane Eranian 1137044330c1SMatt Fleming if (alias->per_pkg) 1138044330c1SMatt Fleming info->per_pkg = true; 113937932c18SAndi Kleen info->metric_expr = alias->metric_expr; 114096284814SAndi Kleen info->metric_name = alias->metric_name; 1141044330c1SMatt Fleming 1142a6146d50SZheng Yan list_del(&term->list); 1143a6146d50SZheng Yan free(term); 1144a6146d50SZheng Yan } 11458a398897SStephane Eranian 11468a398897SStephane Eranian /* 11478a398897SStephane Eranian * if no unit or scale foundin aliases, then 11488a398897SStephane Eranian * set defaults as for evsel 11498a398897SStephane Eranian * unit cannot left to NULL 11508a398897SStephane Eranian */ 115146441bdcSMatt Fleming if (info->unit == NULL) 115246441bdcSMatt Fleming info->unit = ""; 11538a398897SStephane Eranian 115446441bdcSMatt Fleming if (info->scale == 0.0) 115546441bdcSMatt Fleming info->scale = 1.0; 11568a398897SStephane Eranian 1157a6146d50SZheng Yan return 0; 1158a6146d50SZheng Yan } 1159a6146d50SZheng Yan 1160cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1161cd82a32eSJiri Olsa int config, unsigned long *bits) 1162cd82a32eSJiri Olsa { 11635c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1164cd82a32eSJiri Olsa 1165cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1166cd82a32eSJiri Olsa if (!format) 1167cd82a32eSJiri Olsa return -ENOMEM; 1168cd82a32eSJiri Olsa 1169cd82a32eSJiri Olsa format->name = strdup(name); 1170cd82a32eSJiri Olsa format->value = config; 1171cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1172cd82a32eSJiri Olsa 1173cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1174cd82a32eSJiri Olsa return 0; 1175cd82a32eSJiri Olsa } 1176cd82a32eSJiri Olsa 1177cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1178cd82a32eSJiri Olsa { 1179cd82a32eSJiri Olsa long b; 1180cd82a32eSJiri Olsa 1181cd82a32eSJiri Olsa if (!to) 1182cd82a32eSJiri Olsa to = from; 1183cd82a32eSJiri Olsa 118415268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1185cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1186cd82a32eSJiri Olsa set_bit(b, bits); 1187cd82a32eSJiri Olsa } 1188dc098b35SAndi Kleen 1189aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1190aaea3617SCody P Schafer { 1191aaea3617SCody P Schafer if (b > a) 1192aaea3617SCody P Schafer return 0; 1193aaea3617SCody P Schafer return a - b; 1194aaea3617SCody P Schafer } 1195aaea3617SCody P Schafer 1196dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1197dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1198dc098b35SAndi Kleen { 1199aaea3617SCody P Schafer struct parse_events_term *term; 1200aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1201aaea3617SCody P Schafer 1202aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1203aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1204aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1205aaea3617SCody P Schafer ",%s=%s", term->config, 1206aaea3617SCody P Schafer term->val.str); 1207aaea3617SCody P Schafer } 1208aaea3617SCody P Schafer 1209aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1210aaea3617SCody P Schafer buf[used] = '/'; 1211aaea3617SCody P Schafer used++; 1212aaea3617SCody P Schafer } 1213aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1214aaea3617SCody P Schafer buf[used] = '\0'; 1215aaea3617SCody P Schafer used++; 1216aaea3617SCody P Schafer } else 1217aaea3617SCody P Schafer buf[len - 1] = '\0'; 1218aaea3617SCody P Schafer 1219dc098b35SAndi Kleen return buf; 1220dc098b35SAndi Kleen } 1221dc098b35SAndi Kleen 1222dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1223dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1224dc098b35SAndi Kleen { 1225dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1226dc098b35SAndi Kleen return buf; 1227dc098b35SAndi Kleen } 1228dc098b35SAndi Kleen 1229dd5f1036SAndi Kleen struct sevent { 123008e60ed1SAndi Kleen char *name; 123108e60ed1SAndi Kleen char *desc; 1232dd5f1036SAndi Kleen char *topic; 1233f2361024SAndi Kleen char *str; 1234f2361024SAndi Kleen char *pmu; 12357f372a63SAndi Kleen char *metric_expr; 123696284814SAndi Kleen char *metric_name; 123708e60ed1SAndi Kleen }; 123808e60ed1SAndi Kleen 1239dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1240dc098b35SAndi Kleen { 1241dd5f1036SAndi Kleen const struct sevent *as = a; 1242dd5f1036SAndi Kleen const struct sevent *bs = b; 124308e60ed1SAndi Kleen 124408e60ed1SAndi Kleen /* Put extra events last */ 124508e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 124608e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1247dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1248dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1249dd5f1036SAndi Kleen 1250dd5f1036SAndi Kleen if (n) 1251dd5f1036SAndi Kleen return n; 1252dd5f1036SAndi Kleen } 125308e60ed1SAndi Kleen return strcmp(as->name, bs->name); 125408e60ed1SAndi Kleen } 125508e60ed1SAndi Kleen 125608e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 125708e60ed1SAndi Kleen { 125808e60ed1SAndi Kleen int column = start; 125908e60ed1SAndi Kleen int n; 126008e60ed1SAndi Kleen 126108e60ed1SAndi Kleen while (*s) { 126208e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 126308e60ed1SAndi Kleen 126408e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 126508e60ed1SAndi Kleen printf("\n%*s", start, ""); 126608e60ed1SAndi Kleen column = start + corr; 126708e60ed1SAndi Kleen } 126808e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 126908e60ed1SAndi Kleen if (n <= 0) 127008e60ed1SAndi Kleen break; 127108e60ed1SAndi Kleen s += wlen; 127208e60ed1SAndi Kleen column += n; 1273aa4beb10STaeung Song s = ltrim(s); 127408e60ed1SAndi Kleen } 1275dc098b35SAndi Kleen } 1276dc098b35SAndi Kleen 1277c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1278bf874fcfSAndi Kleen bool long_desc, bool details_flag) 1279dc098b35SAndi Kleen { 1280dc098b35SAndi Kleen struct perf_pmu *pmu; 1281dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1282dc098b35SAndi Kleen char buf[1024]; 1283dc098b35SAndi Kleen int printed = 0; 1284dc098b35SAndi Kleen int len, j; 1285dd5f1036SAndi Kleen struct sevent *aliases; 128608e60ed1SAndi Kleen int numdesc = 0; 128761eb2eb4SAndi Kleen int columns = pager_get_columns(); 1288dd5f1036SAndi Kleen char *topic = NULL; 1289dc098b35SAndi Kleen 1290dc098b35SAndi Kleen pmu = NULL; 1291dc098b35SAndi Kleen len = 0; 129242634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1293dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1294dc098b35SAndi Kleen len++; 129542634bc7SAdrian Hunter if (pmu->selectable) 129642634bc7SAdrian Hunter len++; 129742634bc7SAdrian Hunter } 1298dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1299dc098b35SAndi Kleen if (!aliases) 13007e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1301dc098b35SAndi Kleen pmu = NULL; 1302dc098b35SAndi Kleen j = 0; 130342634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1304dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 130508e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 130608e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1307dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1308dc098b35SAndi Kleen 1309dc098b35SAndi Kleen if (event_glob != NULL && 131038d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 131138d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 131267bdc35fSAndi Kleen event_glob)) || 131367bdc35fSAndi Kleen (alias->topic && 131467bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1315dc098b35SAndi Kleen continue; 13167e4772dcSArnaldo Carvalho de Melo 131708e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 13187e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 13197e4772dcSArnaldo Carvalho de Melo 132008e60ed1SAndi Kleen aliases[j].name = name; 132108e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 132208e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 132308e60ed1SAndi Kleen sizeof(buf), 132408e60ed1SAndi Kleen pmu, alias); 132508e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 132608e60ed1SAndi Kleen if (!aliases[j].name) 13277e4772dcSArnaldo Carvalho de Melo goto out_enomem; 132808e60ed1SAndi Kleen 1329c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1330c8d6828aSSukadev Bhattiprolu alias->desc; 1331dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1332f2361024SAndi Kleen aliases[j].str = alias->str; 1333f2361024SAndi Kleen aliases[j].pmu = pmu->name; 13347f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 133596284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1336dc098b35SAndi Kleen j++; 1337dc098b35SAndi Kleen } 1338fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1339fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 13407e4772dcSArnaldo Carvalho de Melo char *s; 13417e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 13427e4772dcSArnaldo Carvalho de Melo goto out_enomem; 134308e60ed1SAndi Kleen aliases[j].name = s; 134442634bc7SAdrian Hunter j++; 134542634bc7SAdrian Hunter } 134642634bc7SAdrian Hunter } 1347dc098b35SAndi Kleen len = j; 1348dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1349dc098b35SAndi Kleen for (j = 0; j < len; j++) { 135015b22ed3SAndi Kleen /* Skip duplicates */ 135115b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 135215b22ed3SAndi Kleen continue; 1353dc098b35SAndi Kleen if (name_only) { 135408e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1355dc098b35SAndi Kleen continue; 1356dc098b35SAndi Kleen } 13571c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 135808e60ed1SAndi Kleen if (numdesc++ == 0) 135908e60ed1SAndi Kleen printf("\n"); 1360dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1361dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1362dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1363dd5f1036SAndi Kleen aliases[j].topic); 1364dd5f1036SAndi Kleen topic = aliases[j].topic; 1365dd5f1036SAndi Kleen } 136608e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 136708e60ed1SAndi Kleen printf("%*s", 8, "["); 136808e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 136908e60ed1SAndi Kleen printf("]\n"); 1370bf874fcfSAndi Kleen if (details_flag) { 13717f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 137296284814SAndi Kleen if (aliases[j].metric_name) 137396284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 13747f372a63SAndi Kleen if (aliases[j].metric_expr) 13757f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 13767f372a63SAndi Kleen putchar('\n'); 13777f372a63SAndi Kleen } 137808e60ed1SAndi Kleen } else 137908e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1380dc098b35SAndi Kleen printed++; 1381dc098b35SAndi Kleen } 1382dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1383dc098b35SAndi Kleen printf("\n"); 13847e4772dcSArnaldo Carvalho de Melo out_free: 13857e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 138608e60ed1SAndi Kleen zfree(&aliases[j].name); 13877e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 13887e4772dcSArnaldo Carvalho de Melo return; 13897e4772dcSArnaldo Carvalho de Melo 13907e4772dcSArnaldo Carvalho de Melo out_enomem: 13917e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 13927e4772dcSArnaldo Carvalho de Melo if (aliases) 13937e4772dcSArnaldo Carvalho de Melo goto out_free; 1394dc098b35SAndi Kleen } 13954cabc3d1SAndi Kleen 13964cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 13974cabc3d1SAndi Kleen { 13984cabc3d1SAndi Kleen struct perf_pmu *pmu; 13994cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 14004cabc3d1SAndi Kleen 14014cabc3d1SAndi Kleen pmu = NULL; 14024cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 14034cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 14044cabc3d1SAndi Kleen continue; 14054cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 14064cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 14074cabc3d1SAndi Kleen return true; 14084cabc3d1SAndi Kleen } 14094cabc3d1SAndi Kleen return false; 14104cabc3d1SAndi Kleen } 14117d4bdab5SAdrian Hunter 14127d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 14137d4bdab5SAdrian Hunter { 14147d4bdab5SAdrian Hunter struct stat st; 14157d4bdab5SAdrian Hunter char path[PATH_MAX]; 14167d4bdab5SAdrian Hunter const char *sysfs; 14177d4bdab5SAdrian Hunter 14187d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 14197d4bdab5SAdrian Hunter if (!sysfs) 14207d4bdab5SAdrian Hunter return NULL; 14217d4bdab5SAdrian Hunter 14227d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 14237d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 14247d4bdab5SAdrian Hunter 14257d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 14267d4bdab5SAdrian Hunter return NULL; 14277d4bdab5SAdrian Hunter 14287d4bdab5SAdrian Hunter return fopen(path, "r"); 14297d4bdab5SAdrian Hunter } 14307d4bdab5SAdrian Hunter 14317d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 14327d4bdab5SAdrian Hunter ...) 14337d4bdab5SAdrian Hunter { 14347d4bdab5SAdrian Hunter va_list args; 14357d4bdab5SAdrian Hunter FILE *file; 14367d4bdab5SAdrian Hunter int ret = EOF; 14377d4bdab5SAdrian Hunter 14387d4bdab5SAdrian Hunter va_start(args, fmt); 14397d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 14407d4bdab5SAdrian Hunter if (file) { 14417d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 14427d4bdab5SAdrian Hunter fclose(file); 14437d4bdab5SAdrian Hunter } 14447d4bdab5SAdrian Hunter va_end(args); 14457d4bdab5SAdrian Hunter return ret; 14467d4bdab5SAdrian Hunter } 1447