1cd82a32eSJiri Olsa #include <linux/list.h> 2c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 3cd82a32eSJiri Olsa #include <sys/types.h> 4cd82a32eSJiri Olsa #include <unistd.h> 5cd82a32eSJiri Olsa #include <stdio.h> 6dc0a6202SAdrian Hunter #include <stdbool.h> 77d4bdab5SAdrian Hunter #include <stdarg.h> 8cd82a32eSJiri Olsa #include <dirent.h> 9cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 10410136f5SStephane Eranian #include <locale.h> 11cd82a32eSJiri Olsa #include "util.h" 12cd82a32eSJiri Olsa #include "pmu.h" 13cd82a32eSJiri Olsa #include "parse-events.h" 147ae92e74SYan, Zheng #include "cpumap.h" 15933f82ffSSukadev Bhattiprolu #include "header.h" 16933f82ffSSukadev Bhattiprolu #include "pmu-events/pmu-events.h" 1761eb2eb4SAndi Kleen #include "cache.h" 18cd82a32eSJiri Olsa 19ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 20ab1bf653SArnaldo Carvalho de Melo char *name; 21ab1bf653SArnaldo Carvalho de Melo int value; 22ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 23ab1bf653SArnaldo Carvalho de Melo struct list_head list; 24ab1bf653SArnaldo Carvalho de Melo }; 25ab1bf653SArnaldo Carvalho de Melo 2650a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 2750a9667cSRobert Richter 28cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 29cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 30cd82a32eSJiri Olsa 31cd82a32eSJiri Olsa static LIST_HEAD(pmus); 32cd82a32eSJiri Olsa 33cd82a32eSJiri Olsa /* 34cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 35cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 36cd82a32eSJiri Olsa */ 37cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 38cd82a32eSJiri Olsa { 39cd82a32eSJiri Olsa struct dirent *evt_ent; 40cd82a32eSJiri Olsa DIR *format_dir; 41cd82a32eSJiri Olsa int ret = 0; 42cd82a32eSJiri Olsa 43cd82a32eSJiri Olsa format_dir = opendir(dir); 44cd82a32eSJiri Olsa if (!format_dir) 45cd82a32eSJiri Olsa return -EINVAL; 46cd82a32eSJiri Olsa 47cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 48cd82a32eSJiri Olsa char path[PATH_MAX]; 49cd82a32eSJiri Olsa char *name = evt_ent->d_name; 50cd82a32eSJiri Olsa FILE *file; 51cd82a32eSJiri Olsa 52cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 53cd82a32eSJiri Olsa continue; 54cd82a32eSJiri Olsa 55cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 56cd82a32eSJiri Olsa 57cd82a32eSJiri Olsa ret = -EINVAL; 58cd82a32eSJiri Olsa file = fopen(path, "r"); 59cd82a32eSJiri Olsa if (!file) 60cd82a32eSJiri Olsa break; 61cd82a32eSJiri Olsa 62cd82a32eSJiri Olsa perf_pmu_in = file; 63cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 64cd82a32eSJiri Olsa fclose(file); 65cd82a32eSJiri Olsa } 66cd82a32eSJiri Olsa 67cd82a32eSJiri Olsa closedir(format_dir); 68cd82a32eSJiri Olsa return ret; 69cd82a32eSJiri Olsa } 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa /* 72cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 73cd82a32eSJiri Olsa * located at: 74cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 75cd82a32eSJiri Olsa */ 76b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 77cd82a32eSJiri Olsa { 78cd82a32eSJiri Olsa struct stat st; 79cd82a32eSJiri Olsa char path[PATH_MAX]; 80cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 81cd82a32eSJiri Olsa 82cd82a32eSJiri Olsa if (!sysfs) 83cd82a32eSJiri Olsa return -1; 84cd82a32eSJiri Olsa 85cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 8650a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 87cd82a32eSJiri Olsa 88cd82a32eSJiri Olsa if (stat(path, &st) < 0) 899bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 90cd82a32eSJiri Olsa 91cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 92cd82a32eSJiri Olsa return -1; 93cd82a32eSJiri Olsa 94cd82a32eSJiri Olsa return 0; 95cd82a32eSJiri Olsa } 96cd82a32eSJiri Olsa 97d02fc6bcSAndi Kleen static int convert_scale(const char *scale, char **end, double *sval) 98d02fc6bcSAndi Kleen { 99d02fc6bcSAndi Kleen char *lc; 100d02fc6bcSAndi Kleen int ret = 0; 101d02fc6bcSAndi Kleen 102d02fc6bcSAndi Kleen /* 103d02fc6bcSAndi Kleen * save current locale 104d02fc6bcSAndi Kleen */ 105d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 106d02fc6bcSAndi Kleen 107d02fc6bcSAndi Kleen /* 108d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 109d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 110d02fc6bcSAndi Kleen * call below. 111d02fc6bcSAndi Kleen */ 112d02fc6bcSAndi Kleen lc = strdup(lc); 113d02fc6bcSAndi Kleen if (!lc) { 114d02fc6bcSAndi Kleen ret = -ENOMEM; 115d02fc6bcSAndi Kleen goto out; 116d02fc6bcSAndi Kleen } 117d02fc6bcSAndi Kleen 118d02fc6bcSAndi Kleen /* 119d02fc6bcSAndi Kleen * force to C locale to ensure kernel 120d02fc6bcSAndi Kleen * scale string is converted correctly. 121d02fc6bcSAndi Kleen * kernel uses default C locale. 122d02fc6bcSAndi Kleen */ 123d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 124d02fc6bcSAndi Kleen 125d02fc6bcSAndi Kleen *sval = strtod(scale, end); 126d02fc6bcSAndi Kleen 127d02fc6bcSAndi Kleen out: 128d02fc6bcSAndi Kleen /* restore locale */ 129d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 130d02fc6bcSAndi Kleen free(lc); 131d02fc6bcSAndi Kleen return ret; 132d02fc6bcSAndi Kleen } 133d02fc6bcSAndi Kleen 134410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 135410136f5SStephane Eranian { 136410136f5SStephane Eranian struct stat st; 137410136f5SStephane Eranian ssize_t sret; 138410136f5SStephane Eranian char scale[128]; 139410136f5SStephane Eranian int fd, ret = -1; 140410136f5SStephane Eranian char path[PATH_MAX]; 141410136f5SStephane Eranian 142410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 143410136f5SStephane Eranian 144410136f5SStephane Eranian fd = open(path, O_RDONLY); 145410136f5SStephane Eranian if (fd == -1) 146410136f5SStephane Eranian return -1; 147410136f5SStephane Eranian 148410136f5SStephane Eranian if (fstat(fd, &st) < 0) 149410136f5SStephane Eranian goto error; 150410136f5SStephane Eranian 151410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 152410136f5SStephane Eranian if (sret < 0) 153410136f5SStephane Eranian goto error; 154410136f5SStephane Eranian 1559ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1569ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1579ecae065SMadhavan Srinivasan else 158410136f5SStephane Eranian scale[sret] = '\0'; 1599ecae065SMadhavan Srinivasan 160d02fc6bcSAndi Kleen ret = convert_scale(scale, NULL, &alias->scale); 161410136f5SStephane Eranian error: 162410136f5SStephane Eranian close(fd); 163410136f5SStephane Eranian return ret; 164410136f5SStephane Eranian } 165410136f5SStephane Eranian 166410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 167410136f5SStephane Eranian { 168410136f5SStephane Eranian char path[PATH_MAX]; 169410136f5SStephane Eranian ssize_t sret; 170410136f5SStephane Eranian int fd; 171410136f5SStephane Eranian 172410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 173410136f5SStephane Eranian 174410136f5SStephane Eranian fd = open(path, O_RDONLY); 175410136f5SStephane Eranian if (fd == -1) 176410136f5SStephane Eranian return -1; 177410136f5SStephane Eranian 178410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 179410136f5SStephane Eranian if (sret < 0) 180410136f5SStephane Eranian goto error; 181410136f5SStephane Eranian 182410136f5SStephane Eranian close(fd); 183410136f5SStephane Eranian 1849ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1859ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1869ecae065SMadhavan Srinivasan else 187410136f5SStephane Eranian alias->unit[sret] = '\0'; 188410136f5SStephane Eranian 189410136f5SStephane Eranian return 0; 190410136f5SStephane Eranian error: 191410136f5SStephane Eranian close(fd); 192410136f5SStephane Eranian alias->unit[0] = '\0'; 193410136f5SStephane Eranian return -1; 194410136f5SStephane Eranian } 195410136f5SStephane Eranian 196044330c1SMatt Fleming static int 197044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 198044330c1SMatt Fleming { 199044330c1SMatt Fleming char path[PATH_MAX]; 200044330c1SMatt Fleming int fd; 201044330c1SMatt Fleming 202044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 203044330c1SMatt Fleming 204044330c1SMatt Fleming fd = open(path, O_RDONLY); 205044330c1SMatt Fleming if (fd == -1) 206044330c1SMatt Fleming return -1; 207044330c1SMatt Fleming 208044330c1SMatt Fleming close(fd); 209044330c1SMatt Fleming 210044330c1SMatt Fleming alias->per_pkg = true; 211044330c1SMatt Fleming return 0; 212044330c1SMatt Fleming } 213044330c1SMatt Fleming 2141d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2151d9e446bSJiri Olsa char *dir, char *name) 2161d9e446bSJiri Olsa { 2171d9e446bSJiri Olsa char path[PATH_MAX]; 2181d9e446bSJiri Olsa int fd; 2191d9e446bSJiri Olsa 2201d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2211d9e446bSJiri Olsa 2221d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2231d9e446bSJiri Olsa if (fd == -1) 2241d9e446bSJiri Olsa return -1; 2251d9e446bSJiri Olsa 2261d9e446bSJiri Olsa alias->snapshot = true; 2271d9e446bSJiri Olsa close(fd); 2281d9e446bSJiri Olsa return 0; 2291d9e446bSJiri Olsa } 2301d9e446bSJiri Olsa 23170c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 232fedb2b51SAndi Kleen char *desc, char *val, 233fedb2b51SAndi Kleen char *long_desc, char *topic, 234fedb2b51SAndi Kleen char *unit, char *perpkg) 235a6146d50SZheng Yan { 2365c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 237a6146d50SZheng Yan int ret; 238fedb2b51SAndi Kleen int num; 239a6146d50SZheng Yan 240a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 241a6146d50SZheng Yan if (!alias) 242a6146d50SZheng Yan return -ENOMEM; 243a6146d50SZheng Yan 244a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 245410136f5SStephane Eranian alias->scale = 1.0; 246410136f5SStephane Eranian alias->unit[0] = '\0'; 247044330c1SMatt Fleming alias->per_pkg = false; 24884530920SStephane Eranian alias->snapshot = false; 249410136f5SStephane Eranian 25070c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 251a6146d50SZheng Yan if (ret) { 25270c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 253a6146d50SZheng Yan free(alias); 254a6146d50SZheng Yan return ret; 255a6146d50SZheng Yan } 256a6146d50SZheng Yan 257a6146d50SZheng Yan alias->name = strdup(name); 25870c646e0SSukadev Bhattiprolu if (dir) { 259410136f5SStephane Eranian /* 260410136f5SStephane Eranian * load unit name and scale if available 261410136f5SStephane Eranian */ 262410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 263410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 264044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2651d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 26670c646e0SSukadev Bhattiprolu } 267410136f5SStephane Eranian 26808e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 269c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 270c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 271dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 272fedb2b51SAndi Kleen if (unit) { 273fedb2b51SAndi Kleen if (convert_scale(unit, &unit, &alias->scale) < 0) 274fedb2b51SAndi Kleen return -1; 275fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 276fedb2b51SAndi Kleen } 277fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 278f2361024SAndi Kleen alias->str = strdup(val); 279f2361024SAndi Kleen 280a6146d50SZheng Yan list_add_tail(&alias->list, list); 281410136f5SStephane Eranian 282a6146d50SZheng Yan return 0; 283a6146d50SZheng Yan } 284a6146d50SZheng Yan 28570c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 28670c646e0SSukadev Bhattiprolu { 28770c646e0SSukadev Bhattiprolu char buf[256]; 28870c646e0SSukadev Bhattiprolu int ret; 28970c646e0SSukadev Bhattiprolu 29070c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 29170c646e0SSukadev Bhattiprolu if (ret == 0) 29270c646e0SSukadev Bhattiprolu return -EINVAL; 29370c646e0SSukadev Bhattiprolu 29470c646e0SSukadev Bhattiprolu buf[ret] = 0; 29570c646e0SSukadev Bhattiprolu 296fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 297fedb2b51SAndi Kleen NULL); 29870c646e0SSukadev Bhattiprolu } 29970c646e0SSukadev Bhattiprolu 30046441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 30146441bdcSMatt Fleming { 30246441bdcSMatt Fleming size_t len; 30346441bdcSMatt Fleming 30446441bdcSMatt Fleming len = strlen(name); 30546441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 30646441bdcSMatt Fleming return true; 30746441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 30846441bdcSMatt Fleming return true; 309044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 310044330c1SMatt Fleming return true; 3111d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 3121d9e446bSJiri Olsa return true; 31346441bdcSMatt Fleming 31446441bdcSMatt Fleming return false; 31546441bdcSMatt Fleming } 31646441bdcSMatt Fleming 317a6146d50SZheng Yan /* 318a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 319a6146d50SZheng Yan * specified in 'dir' parameter. 320a6146d50SZheng Yan */ 321a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 322a6146d50SZheng Yan { 323a6146d50SZheng Yan struct dirent *evt_ent; 324a6146d50SZheng Yan DIR *event_dir; 325a6146d50SZheng Yan 326a6146d50SZheng Yan event_dir = opendir(dir); 327a6146d50SZheng Yan if (!event_dir) 328a6146d50SZheng Yan return -EINVAL; 329a6146d50SZheng Yan 330940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 331a6146d50SZheng Yan char path[PATH_MAX]; 332a6146d50SZheng Yan char *name = evt_ent->d_name; 333a6146d50SZheng Yan FILE *file; 334a6146d50SZheng Yan 335a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 336a6146d50SZheng Yan continue; 337a6146d50SZheng Yan 338410136f5SStephane Eranian /* 33946441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 340410136f5SStephane Eranian */ 34146441bdcSMatt Fleming if (pmu_alias_info_file(name)) 342410136f5SStephane Eranian continue; 343410136f5SStephane Eranian 344a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 345a6146d50SZheng Yan 346a6146d50SZheng Yan file = fopen(path, "r"); 347940db6dcSAndi Kleen if (!file) { 348940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 349940db6dcSAndi Kleen continue; 350940db6dcSAndi Kleen } 351410136f5SStephane Eranian 352940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 353940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 354a6146d50SZheng Yan fclose(file); 355a6146d50SZheng Yan } 356a6146d50SZheng Yan 357a6146d50SZheng Yan closedir(event_dir); 358940db6dcSAndi Kleen return 0; 359a6146d50SZheng Yan } 360a6146d50SZheng Yan 361a6146d50SZheng Yan /* 362a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 363a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 364a6146d50SZheng Yan */ 365b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 366a6146d50SZheng Yan { 367a6146d50SZheng Yan struct stat st; 368a6146d50SZheng Yan char path[PATH_MAX]; 369cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 370a6146d50SZheng Yan 371a6146d50SZheng Yan if (!sysfs) 372a6146d50SZheng Yan return -1; 373a6146d50SZheng Yan 374a6146d50SZheng Yan snprintf(path, PATH_MAX, 375a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 376a6146d50SZheng Yan 377a6146d50SZheng Yan if (stat(path, &st) < 0) 3783fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 379a6146d50SZheng Yan 380a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 381a6146d50SZheng Yan return -1; 382a6146d50SZheng Yan 383a6146d50SZheng Yan return 0; 384a6146d50SZheng Yan } 385a6146d50SZheng Yan 3865c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 387a6146d50SZheng Yan struct list_head *terms) 388a6146d50SZheng Yan { 3897c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 390a6146d50SZheng Yan LIST_HEAD(list); 391a6146d50SZheng Yan int ret; 392a6146d50SZheng Yan 393a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 3947c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 395a6146d50SZheng Yan if (ret) { 396682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 397a6146d50SZheng Yan return ret; 398a6146d50SZheng Yan } 3997c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 400a6146d50SZheng Yan } 401a6146d50SZheng Yan list_splice(&list, terms); 402a6146d50SZheng Yan return 0; 403a6146d50SZheng Yan } 404a6146d50SZheng Yan 405cd82a32eSJiri Olsa /* 406cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 407cd82a32eSJiri Olsa * located at: 408cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 409cd82a32eSJiri Olsa */ 410b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 411cd82a32eSJiri Olsa { 412cd82a32eSJiri Olsa struct stat st; 413cd82a32eSJiri Olsa char path[PATH_MAX]; 414cd82a32eSJiri Olsa FILE *file; 415cd82a32eSJiri Olsa int ret = 0; 416cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 417cd82a32eSJiri Olsa 418cd82a32eSJiri Olsa if (!sysfs) 419cd82a32eSJiri Olsa return -1; 420cd82a32eSJiri Olsa 421cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 42250a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 423cd82a32eSJiri Olsa 424cd82a32eSJiri Olsa if (stat(path, &st) < 0) 425cd82a32eSJiri Olsa return -1; 426cd82a32eSJiri Olsa 427cd82a32eSJiri Olsa file = fopen(path, "r"); 428cd82a32eSJiri Olsa if (!file) 429cd82a32eSJiri Olsa return -EINVAL; 430cd82a32eSJiri Olsa 431cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 432cd82a32eSJiri Olsa ret = -1; 433cd82a32eSJiri Olsa 434cd82a32eSJiri Olsa fclose(file); 435cd82a32eSJiri Olsa return ret; 436cd82a32eSJiri Olsa } 437cd82a32eSJiri Olsa 43850a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 43950a9667cSRobert Richter static void pmu_read_sysfs(void) 44050a9667cSRobert Richter { 44150a9667cSRobert Richter char path[PATH_MAX]; 44250a9667cSRobert Richter DIR *dir; 44350a9667cSRobert Richter struct dirent *dent; 444cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 44550a9667cSRobert Richter 44650a9667cSRobert Richter if (!sysfs) 44750a9667cSRobert Richter return; 44850a9667cSRobert Richter 44950a9667cSRobert Richter snprintf(path, PATH_MAX, 45050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 45150a9667cSRobert Richter 45250a9667cSRobert Richter dir = opendir(path); 45350a9667cSRobert Richter if (!dir) 45450a9667cSRobert Richter return; 45550a9667cSRobert Richter 45650a9667cSRobert Richter while ((dent = readdir(dir))) { 45750a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 45850a9667cSRobert Richter continue; 45950a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 46050a9667cSRobert Richter perf_pmu__find(dent->d_name); 46150a9667cSRobert Richter } 46250a9667cSRobert Richter 46350a9667cSRobert Richter closedir(dir); 46450a9667cSRobert Richter } 46550a9667cSRobert Richter 466b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 4677ae92e74SYan, Zheng { 4687ae92e74SYan, Zheng struct stat st; 4697ae92e74SYan, Zheng char path[PATH_MAX]; 4707ae92e74SYan, Zheng FILE *file; 4717ae92e74SYan, Zheng struct cpu_map *cpus; 472cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 4737e3fcffeSMark Rutland const char *templates[] = { 4747e3fcffeSMark Rutland "%s/bus/event_source/devices/%s/cpumask", 4757e3fcffeSMark Rutland "%s/bus/event_source/devices/%s/cpus", 4767e3fcffeSMark Rutland NULL 4777e3fcffeSMark Rutland }; 4787e3fcffeSMark Rutland const char **template; 4797ae92e74SYan, Zheng 4807ae92e74SYan, Zheng if (!sysfs) 4817ae92e74SYan, Zheng return NULL; 4827ae92e74SYan, Zheng 4837e3fcffeSMark Rutland for (template = templates; *template; template++) { 4847e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 4857e3fcffeSMark Rutland if (stat(path, &st) == 0) 4867e3fcffeSMark Rutland break; 4877e3fcffeSMark Rutland } 4887ae92e74SYan, Zheng 4897e3fcffeSMark Rutland if (!*template) 4907ae92e74SYan, Zheng return NULL; 4917ae92e74SYan, Zheng 4927ae92e74SYan, Zheng file = fopen(path, "r"); 4937ae92e74SYan, Zheng if (!file) 4947ae92e74SYan, Zheng return NULL; 4957ae92e74SYan, Zheng 4967ae92e74SYan, Zheng cpus = cpu_map__read(file); 4977ae92e74SYan, Zheng fclose(file); 4987ae92e74SYan, Zheng return cpus; 4997ae92e74SYan, Zheng } 5007ae92e74SYan, Zheng 501933f82ffSSukadev Bhattiprolu /* 502933f82ffSSukadev Bhattiprolu * Return the CPU id as a raw string. 503933f82ffSSukadev Bhattiprolu * 504933f82ffSSukadev Bhattiprolu * Each architecture should provide a more precise id string that 505933f82ffSSukadev Bhattiprolu * can be use to match the architecture's "mapfile". 506933f82ffSSukadev Bhattiprolu */ 507933f82ffSSukadev Bhattiprolu char * __weak get_cpuid_str(void) 508933f82ffSSukadev Bhattiprolu { 509933f82ffSSukadev Bhattiprolu return NULL; 510933f82ffSSukadev Bhattiprolu } 511933f82ffSSukadev Bhattiprolu 512933f82ffSSukadev Bhattiprolu /* 513933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 514933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 515933f82ffSSukadev Bhattiprolu * as aliases. 516933f82ffSSukadev Bhattiprolu */ 517fedb2b51SAndi Kleen static void pmu_add_cpu_aliases(struct list_head *head, const char *name) 518933f82ffSSukadev Bhattiprolu { 519933f82ffSSukadev Bhattiprolu int i; 520933f82ffSSukadev Bhattiprolu struct pmu_events_map *map; 521933f82ffSSukadev Bhattiprolu struct pmu_event *pe; 522933f82ffSSukadev Bhattiprolu char *cpuid; 523fb967063SAndi Kleen static bool printed; 524933f82ffSSukadev Bhattiprolu 525fc06e2a5SAndi Kleen cpuid = getenv("PERF_CPUID"); 526fc06e2a5SAndi Kleen if (cpuid) 527fc06e2a5SAndi Kleen cpuid = strdup(cpuid); 528fc06e2a5SAndi Kleen if (!cpuid) 529933f82ffSSukadev Bhattiprolu cpuid = get_cpuid_str(); 530933f82ffSSukadev Bhattiprolu if (!cpuid) 531933f82ffSSukadev Bhattiprolu return; 532933f82ffSSukadev Bhattiprolu 533fb967063SAndi Kleen if (!printed) { 534fc06e2a5SAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 535fb967063SAndi Kleen printed = true; 536fb967063SAndi Kleen } 537fc06e2a5SAndi Kleen 538933f82ffSSukadev Bhattiprolu i = 0; 539933f82ffSSukadev Bhattiprolu while (1) { 540933f82ffSSukadev Bhattiprolu map = &pmu_events_map[i++]; 541933f82ffSSukadev Bhattiprolu if (!map->table) 542933f82ffSSukadev Bhattiprolu goto out; 543933f82ffSSukadev Bhattiprolu 544933f82ffSSukadev Bhattiprolu if (!strcmp(map->cpuid, cpuid)) 545933f82ffSSukadev Bhattiprolu break; 546933f82ffSSukadev Bhattiprolu } 547933f82ffSSukadev Bhattiprolu 548933f82ffSSukadev Bhattiprolu /* 549933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 550933f82ffSSukadev Bhattiprolu */ 551933f82ffSSukadev Bhattiprolu i = 0; 552933f82ffSSukadev Bhattiprolu while (1) { 553fedb2b51SAndi Kleen const char *pname; 554fedb2b51SAndi Kleen 555933f82ffSSukadev Bhattiprolu pe = &map->table[i++]; 556933f82ffSSukadev Bhattiprolu if (!pe->name) 557933f82ffSSukadev Bhattiprolu break; 558933f82ffSSukadev Bhattiprolu 559fedb2b51SAndi Kleen pname = pe->pmu ? pe->pmu : "cpu"; 560fedb2b51SAndi Kleen if (strncmp(pname, name, strlen(pname))) 561fedb2b51SAndi Kleen continue; 562fedb2b51SAndi Kleen 563933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 564933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 565c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 566fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 567fedb2b51SAndi Kleen (char *)pe->unit, (char *)pe->perpkg); 568933f82ffSSukadev Bhattiprolu } 569933f82ffSSukadev Bhattiprolu 570933f82ffSSukadev Bhattiprolu out: 571933f82ffSSukadev Bhattiprolu free(cpuid); 572933f82ffSSukadev Bhattiprolu } 573933f82ffSSukadev Bhattiprolu 574c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 575dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 576dc0a6202SAdrian Hunter { 577dc0a6202SAdrian Hunter return NULL; 578dc0a6202SAdrian Hunter } 579dc0a6202SAdrian Hunter 580b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 581cd82a32eSJiri Olsa { 582cd82a32eSJiri Olsa struct perf_pmu *pmu; 583cd82a32eSJiri Olsa LIST_HEAD(format); 584a6146d50SZheng Yan LIST_HEAD(aliases); 585cd82a32eSJiri Olsa __u32 type; 586cd82a32eSJiri Olsa 587cd82a32eSJiri Olsa /* 588cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 589cd82a32eSJiri Olsa * type value and format definitions. Load both right 590cd82a32eSJiri Olsa * now. 591cd82a32eSJiri Olsa */ 592cd82a32eSJiri Olsa if (pmu_format(name, &format)) 593cd82a32eSJiri Olsa return NULL; 594cd82a32eSJiri Olsa 59515b22ed3SAndi Kleen /* 59615b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 59715b22ed3SAndi Kleen */ 59815b22ed3SAndi Kleen if (pmu_type(name, &type)) 59915b22ed3SAndi Kleen return NULL; 60015b22ed3SAndi Kleen 6013fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 6023fded963SJiri Olsa return NULL; 6033fded963SJiri Olsa 604fedb2b51SAndi Kleen pmu_add_cpu_aliases(&aliases, name); 605cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 606cd82a32eSJiri Olsa if (!pmu) 607cd82a32eSJiri Olsa return NULL; 608cd82a32eSJiri Olsa 6097ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 6107ae92e74SYan, Zheng 611cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 612a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 613cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 614a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 615cd82a32eSJiri Olsa pmu->name = strdup(name); 616cd82a32eSJiri Olsa pmu->type = type; 6179bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 618dc0a6202SAdrian Hunter 619dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 620dc0a6202SAdrian Hunter 621cd82a32eSJiri Olsa return pmu; 622cd82a32eSJiri Olsa } 623cd82a32eSJiri Olsa 624b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 625cd82a32eSJiri Olsa { 626cd82a32eSJiri Olsa struct perf_pmu *pmu; 627cd82a32eSJiri Olsa 628cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 629cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 630cd82a32eSJiri Olsa return pmu; 631cd82a32eSJiri Olsa 632cd82a32eSJiri Olsa return NULL; 633cd82a32eSJiri Olsa } 634cd82a32eSJiri Olsa 63550a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 63650a9667cSRobert Richter { 63750a9667cSRobert Richter /* 63850a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 63950a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 64050a9667cSRobert Richter */ 64150a9667cSRobert Richter if (!pmu) { 64250a9667cSRobert Richter pmu_read_sysfs(); 64350a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 64450a9667cSRobert Richter } 64550a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 64650a9667cSRobert Richter return pmu; 64750a9667cSRobert Richter return NULL; 64850a9667cSRobert Richter } 64950a9667cSRobert Richter 650b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 651cd82a32eSJiri Olsa { 652cd82a32eSJiri Olsa struct perf_pmu *pmu; 653cd82a32eSJiri Olsa 654cd82a32eSJiri Olsa /* 655cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 656cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 657cd82a32eSJiri Olsa * the pmu format definitions. 658cd82a32eSJiri Olsa */ 659cd82a32eSJiri Olsa pmu = pmu_find(name); 660cd82a32eSJiri Olsa if (pmu) 661cd82a32eSJiri Olsa return pmu; 662cd82a32eSJiri Olsa 663cd82a32eSJiri Olsa return pmu_lookup(name); 664cd82a32eSJiri Olsa } 665cd82a32eSJiri Olsa 6665c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 66709ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 668cd82a32eSJiri Olsa { 6695c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 670cd82a32eSJiri Olsa 671cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 672cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 673cd82a32eSJiri Olsa return format; 674cd82a32eSJiri Olsa 675cd82a32eSJiri Olsa return NULL; 676cd82a32eSJiri Olsa } 677cd82a32eSJiri Olsa 67809ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 67909ff6071SAdrian Hunter { 68009ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 68109ff6071SAdrian Hunter __u64 bits = 0; 68209ff6071SAdrian Hunter int fbit; 68309ff6071SAdrian Hunter 68409ff6071SAdrian Hunter if (!format) 68509ff6071SAdrian Hunter return 0; 68609ff6071SAdrian Hunter 68709ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 68809ff6071SAdrian Hunter bits |= 1ULL << fbit; 68909ff6071SAdrian Hunter 69009ff6071SAdrian Hunter return bits; 69109ff6071SAdrian Hunter } 69209ff6071SAdrian Hunter 693cd82a32eSJiri Olsa /* 694dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 695cd82a32eSJiri Olsa * and unformated value (value parameter). 696cd82a32eSJiri Olsa */ 697dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 698dc0a6202SAdrian Hunter bool zero) 699cd82a32eSJiri Olsa { 700cd82a32eSJiri Olsa unsigned long fbit, vbit; 701cd82a32eSJiri Olsa 702cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 703cd82a32eSJiri Olsa 704cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 705cd82a32eSJiri Olsa continue; 706cd82a32eSJiri Olsa 707dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 708dc0a6202SAdrian Hunter *v |= (1llu << fbit); 709dc0a6202SAdrian Hunter else if (zero) 710dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 711cd82a32eSJiri Olsa } 712cd82a32eSJiri Olsa } 713cd82a32eSJiri Olsa 7140efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 7150efe6b67SAdrian Hunter { 716ac0e2cd5SKan Liang __u64 w = 0; 717ac0e2cd5SKan Liang int fbit; 7180efe6b67SAdrian Hunter 719ac0e2cd5SKan Liang for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) 720ac0e2cd5SKan Liang w |= (1ULL << fbit); 721ac0e2cd5SKan Liang 722ac0e2cd5SKan Liang return w; 7230efe6b67SAdrian Hunter } 7240efe6b67SAdrian Hunter 725cd82a32eSJiri Olsa /* 726688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 727688d4dfcSCody P Schafer * in the remaining terms. 728688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 729688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 730688d4dfcSCody P Schafer * in a config string) later on in the term list. 731688d4dfcSCody P Schafer */ 732688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 733688d4dfcSCody P Schafer struct list_head *head_terms, 734688d4dfcSCody P Schafer __u64 *value) 735688d4dfcSCody P Schafer { 736688d4dfcSCody P Schafer struct parse_events_term *t; 737688d4dfcSCody P Schafer 738688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 739688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 740688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 741688d4dfcSCody P Schafer t->used = true; 742688d4dfcSCody P Schafer *value = t->val.num; 743688d4dfcSCody P Schafer return 0; 744688d4dfcSCody P Schafer } 745688d4dfcSCody P Schafer } 746688d4dfcSCody P Schafer } 747688d4dfcSCody P Schafer 748688d4dfcSCody P Schafer if (verbose) 749688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 750688d4dfcSCody P Schafer 751688d4dfcSCody P Schafer return -1; 752688d4dfcSCody P Schafer } 753688d4dfcSCody P Schafer 754ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 755e64b020bSJiri Olsa { 756e64b020bSJiri Olsa struct perf_pmu_format *format; 75711db4e29SMasami Hiramatsu char *str = NULL; 75811db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 759e64b020bSJiri Olsa unsigned i = 0; 760e64b020bSJiri Olsa 761ffeb883eSHe Kuang if (!formats) 762e64b020bSJiri Olsa return NULL; 763e64b020bSJiri Olsa 764e64b020bSJiri Olsa /* sysfs exported terms */ 765ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 76611db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 76711db4e29SMasami Hiramatsu goto error; 768e64b020bSJiri Olsa 769ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 77011db4e29SMasami Hiramatsu error: 771ffeb883eSHe Kuang strbuf_release(&buf); 772e64b020bSJiri Olsa 773e64b020bSJiri Olsa return str; 774e64b020bSJiri Olsa } 775e64b020bSJiri Olsa 776688d4dfcSCody P Schafer /* 777cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 77888aca8d9SCody P Schafer * user input data - term parameter. 779cd82a32eSJiri Olsa */ 780cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 781cd82a32eSJiri Olsa struct perf_event_attr *attr, 782dc0a6202SAdrian Hunter struct parse_events_term *term, 783688d4dfcSCody P Schafer struct list_head *head_terms, 784e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 785cd82a32eSJiri Olsa { 7865c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 787cd82a32eSJiri Olsa __u64 *vp; 7880efe6b67SAdrian Hunter __u64 val, max_val; 789cd82a32eSJiri Olsa 790cd82a32eSJiri Olsa /* 791688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 792688d4dfcSCody P Schafer * skip it in normal eval. 793688d4dfcSCody P Schafer */ 794688d4dfcSCody P Schafer if (term->used) 795688d4dfcSCody P Schafer return 0; 796688d4dfcSCody P Schafer 797688d4dfcSCody P Schafer /* 798cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 799cd82a32eSJiri Olsa * to be done for them. 800cd82a32eSJiri Olsa */ 801cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 802cd82a32eSJiri Olsa return 0; 803cd82a32eSJiri Olsa 804cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 805688d4dfcSCody P Schafer if (!format) { 806688d4dfcSCody P Schafer if (verbose) 807688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 808e64b020bSJiri Olsa if (err) { 809ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 810ffeb883eSHe Kuang 811e64b020bSJiri Olsa err->idx = term->err_term; 812e64b020bSJiri Olsa err->str = strdup("unknown term"); 813ffeb883eSHe Kuang err->help = parse_events_formats_error_string(pmu_term); 814ffeb883eSHe Kuang free(pmu_term); 815e64b020bSJiri Olsa } 816cd82a32eSJiri Olsa return -EINVAL; 817688d4dfcSCody P Schafer } 818cd82a32eSJiri Olsa 819cd82a32eSJiri Olsa switch (format->value) { 820cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 821cd82a32eSJiri Olsa vp = &attr->config; 822cd82a32eSJiri Olsa break; 823cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 824cd82a32eSJiri Olsa vp = &attr->config1; 825cd82a32eSJiri Olsa break; 826cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 827cd82a32eSJiri Olsa vp = &attr->config2; 828cd82a32eSJiri Olsa break; 829cd82a32eSJiri Olsa default: 830cd82a32eSJiri Olsa return -EINVAL; 831cd82a32eSJiri Olsa } 832cd82a32eSJiri Olsa 83316fa7e82SJiri Olsa /* 834688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 835688d4dfcSCody P Schafer * using event parameters. 83616fa7e82SJiri Olsa */ 837688d4dfcSCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 838688d4dfcSCody P Schafer val = term->val.num; 839688d4dfcSCody P Schafer else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 840688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 841e64b020bSJiri Olsa if (verbose) { 842688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 843688d4dfcSCody P Schafer term->config, term->val.str); 844e64b020bSJiri Olsa } 845e64b020bSJiri Olsa if (err) { 846e64b020bSJiri Olsa err->idx = term->err_val; 847e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 848e64b020bSJiri Olsa } 849688d4dfcSCody P Schafer return -EINVAL; 850688d4dfcSCody P Schafer } 851688d4dfcSCody P Schafer 852688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 853688d4dfcSCody P Schafer return -EINVAL; 854688d4dfcSCody P Schafer } else 855688d4dfcSCody P Schafer return -EINVAL; 856688d4dfcSCody P Schafer 8570efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 8580efe6b67SAdrian Hunter if (val > max_val) { 8590efe6b67SAdrian Hunter if (err) { 8600efe6b67SAdrian Hunter err->idx = term->err_val; 8610efe6b67SAdrian Hunter if (asprintf(&err->str, 8620efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 8630efe6b67SAdrian Hunter (unsigned long long)max_val) < 0) 8640efe6b67SAdrian Hunter err->str = strdup("value too big for format"); 8650efe6b67SAdrian Hunter return -EINVAL; 8660efe6b67SAdrian Hunter } 8670efe6b67SAdrian Hunter /* 8680efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 8690efe6b67SAdrian Hunter * silently truncated. 8700efe6b67SAdrian Hunter */ 8710efe6b67SAdrian Hunter } 8720efe6b67SAdrian Hunter 873688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 874cd82a32eSJiri Olsa return 0; 875cd82a32eSJiri Olsa } 876cd82a32eSJiri Olsa 877cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 878cff7f956SJiri Olsa struct perf_event_attr *attr, 879dc0a6202SAdrian Hunter struct list_head *head_terms, 880e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 881cd82a32eSJiri Olsa { 8826cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 883cd82a32eSJiri Olsa 884688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 885e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 886e64b020bSJiri Olsa zero, err)) 887cd82a32eSJiri Olsa return -EINVAL; 888688d4dfcSCody P Schafer } 889cd82a32eSJiri Olsa 890cd82a32eSJiri Olsa return 0; 891cd82a32eSJiri Olsa } 892cd82a32eSJiri Olsa 893cd82a32eSJiri Olsa /* 894cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 895cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 896cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 897cd82a32eSJiri Olsa */ 898cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 899e64b020bSJiri Olsa struct list_head *head_terms, 900e64b020bSJiri Olsa struct parse_events_error *err) 901cd82a32eSJiri Olsa { 902dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 903dc0a6202SAdrian Hunter 904cd82a32eSJiri Olsa attr->type = pmu->type; 905e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 906e64b020bSJiri Olsa zero, err); 907cd82a32eSJiri Olsa } 908cd82a32eSJiri Olsa 9095c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 9106cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 911a6146d50SZheng Yan { 9125c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 913a6146d50SZheng Yan char *name; 914a6146d50SZheng Yan 915a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 916a6146d50SZheng Yan return NULL; 917a6146d50SZheng Yan 918a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 919a6146d50SZheng Yan if (term->val.num != 1) 920a6146d50SZheng Yan return NULL; 921a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 922a6146d50SZheng Yan return NULL; 923a6146d50SZheng Yan name = term->config; 924a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 925a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 926a6146d50SZheng Yan return NULL; 927a6146d50SZheng Yan name = term->val.str; 928a6146d50SZheng Yan } else { 929a6146d50SZheng Yan return NULL; 930a6146d50SZheng Yan } 931a6146d50SZheng Yan 932a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 933a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 934a6146d50SZheng Yan return alias; 935a6146d50SZheng Yan } 936a6146d50SZheng Yan return NULL; 937a6146d50SZheng Yan } 938a6146d50SZheng Yan 939410136f5SStephane Eranian 9401d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 9411d9e446bSJiri Olsa struct perf_pmu_info *info) 942410136f5SStephane Eranian { 943410136f5SStephane Eranian /* 944410136f5SStephane Eranian * Only one term in event definition can 9451d9e446bSJiri Olsa * define unit, scale and snapshot, fail 9461d9e446bSJiri Olsa * if there's more than one. 947410136f5SStephane Eranian */ 9481d9e446bSJiri Olsa if ((info->unit && alias->unit) || 9491d9e446bSJiri Olsa (info->scale && alias->scale) || 9501d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 951410136f5SStephane Eranian return -EINVAL; 952410136f5SStephane Eranian 953410136f5SStephane Eranian if (alias->unit) 9541d9e446bSJiri Olsa info->unit = alias->unit; 955410136f5SStephane Eranian 956410136f5SStephane Eranian if (alias->scale) 9571d9e446bSJiri Olsa info->scale = alias->scale; 9581d9e446bSJiri Olsa 9591d9e446bSJiri Olsa if (alias->snapshot) 9601d9e446bSJiri Olsa info->snapshot = alias->snapshot; 961410136f5SStephane Eranian 962410136f5SStephane Eranian return 0; 963410136f5SStephane Eranian } 964410136f5SStephane Eranian 965a6146d50SZheng Yan /* 966a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 967a6146d50SZheng Yan * defined for the alias 968a6146d50SZheng Yan */ 969410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 97046441bdcSMatt Fleming struct perf_pmu_info *info) 971a6146d50SZheng Yan { 9726cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 9735c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 974a6146d50SZheng Yan int ret; 975a6146d50SZheng Yan 976044330c1SMatt Fleming info->per_pkg = false; 977044330c1SMatt Fleming 9788a398897SStephane Eranian /* 9798a398897SStephane Eranian * Mark unit and scale as not set 9808a398897SStephane Eranian * (different from default values, see below) 9818a398897SStephane Eranian */ 98246441bdcSMatt Fleming info->unit = NULL; 98346441bdcSMatt Fleming info->scale = 0.0; 9841d9e446bSJiri Olsa info->snapshot = false; 985410136f5SStephane Eranian 986a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 987a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 988a6146d50SZheng Yan if (!alias) 989a6146d50SZheng Yan continue; 990a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 991a6146d50SZheng Yan if (ret) 992a6146d50SZheng Yan return ret; 993410136f5SStephane Eranian 9941d9e446bSJiri Olsa ret = check_info_data(alias, info); 995410136f5SStephane Eranian if (ret) 996410136f5SStephane Eranian return ret; 997410136f5SStephane Eranian 998044330c1SMatt Fleming if (alias->per_pkg) 999044330c1SMatt Fleming info->per_pkg = true; 1000044330c1SMatt Fleming 1001a6146d50SZheng Yan list_del(&term->list); 1002a6146d50SZheng Yan free(term); 1003a6146d50SZheng Yan } 10048a398897SStephane Eranian 10058a398897SStephane Eranian /* 10068a398897SStephane Eranian * if no unit or scale foundin aliases, then 10078a398897SStephane Eranian * set defaults as for evsel 10088a398897SStephane Eranian * unit cannot left to NULL 10098a398897SStephane Eranian */ 101046441bdcSMatt Fleming if (info->unit == NULL) 101146441bdcSMatt Fleming info->unit = ""; 10128a398897SStephane Eranian 101346441bdcSMatt Fleming if (info->scale == 0.0) 101446441bdcSMatt Fleming info->scale = 1.0; 10158a398897SStephane Eranian 1016a6146d50SZheng Yan return 0; 1017a6146d50SZheng Yan } 1018a6146d50SZheng Yan 1019cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1020cd82a32eSJiri Olsa int config, unsigned long *bits) 1021cd82a32eSJiri Olsa { 10225c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1023cd82a32eSJiri Olsa 1024cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1025cd82a32eSJiri Olsa if (!format) 1026cd82a32eSJiri Olsa return -ENOMEM; 1027cd82a32eSJiri Olsa 1028cd82a32eSJiri Olsa format->name = strdup(name); 1029cd82a32eSJiri Olsa format->value = config; 1030cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1031cd82a32eSJiri Olsa 1032cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1033cd82a32eSJiri Olsa return 0; 1034cd82a32eSJiri Olsa } 1035cd82a32eSJiri Olsa 1036cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1037cd82a32eSJiri Olsa { 1038cd82a32eSJiri Olsa long b; 1039cd82a32eSJiri Olsa 1040cd82a32eSJiri Olsa if (!to) 1041cd82a32eSJiri Olsa to = from; 1042cd82a32eSJiri Olsa 104315268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1044cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1045cd82a32eSJiri Olsa set_bit(b, bits); 1046cd82a32eSJiri Olsa } 1047dc098b35SAndi Kleen 1048aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1049aaea3617SCody P Schafer { 1050aaea3617SCody P Schafer if (b > a) 1051aaea3617SCody P Schafer return 0; 1052aaea3617SCody P Schafer return a - b; 1053aaea3617SCody P Schafer } 1054aaea3617SCody P Schafer 1055dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1056dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1057dc098b35SAndi Kleen { 1058aaea3617SCody P Schafer struct parse_events_term *term; 1059aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1060aaea3617SCody P Schafer 1061aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1062aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1063aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1064aaea3617SCody P Schafer ",%s=%s", term->config, 1065aaea3617SCody P Schafer term->val.str); 1066aaea3617SCody P Schafer } 1067aaea3617SCody P Schafer 1068aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1069aaea3617SCody P Schafer buf[used] = '/'; 1070aaea3617SCody P Schafer used++; 1071aaea3617SCody P Schafer } 1072aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1073aaea3617SCody P Schafer buf[used] = '\0'; 1074aaea3617SCody P Schafer used++; 1075aaea3617SCody P Schafer } else 1076aaea3617SCody P Schafer buf[len - 1] = '\0'; 1077aaea3617SCody P Schafer 1078dc098b35SAndi Kleen return buf; 1079dc098b35SAndi Kleen } 1080dc098b35SAndi Kleen 1081dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1082dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1083dc098b35SAndi Kleen { 1084dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1085dc098b35SAndi Kleen return buf; 1086dc098b35SAndi Kleen } 1087dc098b35SAndi Kleen 1088dd5f1036SAndi Kleen struct sevent { 108908e60ed1SAndi Kleen char *name; 109008e60ed1SAndi Kleen char *desc; 1091dd5f1036SAndi Kleen char *topic; 1092f2361024SAndi Kleen char *str; 1093f2361024SAndi Kleen char *pmu; 109408e60ed1SAndi Kleen }; 109508e60ed1SAndi Kleen 1096dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1097dc098b35SAndi Kleen { 1098dd5f1036SAndi Kleen const struct sevent *as = a; 1099dd5f1036SAndi Kleen const struct sevent *bs = b; 110008e60ed1SAndi Kleen 110108e60ed1SAndi Kleen /* Put extra events last */ 110208e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 110308e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1104dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1105dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1106dd5f1036SAndi Kleen 1107dd5f1036SAndi Kleen if (n) 1108dd5f1036SAndi Kleen return n; 1109dd5f1036SAndi Kleen } 111008e60ed1SAndi Kleen return strcmp(as->name, bs->name); 111108e60ed1SAndi Kleen } 111208e60ed1SAndi Kleen 111308e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 111408e60ed1SAndi Kleen { 111508e60ed1SAndi Kleen int column = start; 111608e60ed1SAndi Kleen int n; 111708e60ed1SAndi Kleen 111808e60ed1SAndi Kleen while (*s) { 111908e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 112008e60ed1SAndi Kleen 112108e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 112208e60ed1SAndi Kleen printf("\n%*s", start, ""); 112308e60ed1SAndi Kleen column = start + corr; 112408e60ed1SAndi Kleen } 112508e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 112608e60ed1SAndi Kleen if (n <= 0) 112708e60ed1SAndi Kleen break; 112808e60ed1SAndi Kleen s += wlen; 112908e60ed1SAndi Kleen column += n; 113008e60ed1SAndi Kleen while (isspace(*s)) 113108e60ed1SAndi Kleen s++; 113208e60ed1SAndi Kleen } 1133dc098b35SAndi Kleen } 1134dc098b35SAndi Kleen 1135c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1136c8d6828aSSukadev Bhattiprolu bool long_desc) 1137dc098b35SAndi Kleen { 1138dc098b35SAndi Kleen struct perf_pmu *pmu; 1139dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1140dc098b35SAndi Kleen char buf[1024]; 1141dc098b35SAndi Kleen int printed = 0; 1142dc098b35SAndi Kleen int len, j; 1143dd5f1036SAndi Kleen struct sevent *aliases; 114408e60ed1SAndi Kleen int numdesc = 0; 114561eb2eb4SAndi Kleen int columns = pager_get_columns(); 1146dd5f1036SAndi Kleen char *topic = NULL; 1147dc098b35SAndi Kleen 1148dc098b35SAndi Kleen pmu = NULL; 1149dc098b35SAndi Kleen len = 0; 115042634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1151dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1152dc098b35SAndi Kleen len++; 115342634bc7SAdrian Hunter if (pmu->selectable) 115442634bc7SAdrian Hunter len++; 115542634bc7SAdrian Hunter } 1156dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1157dc098b35SAndi Kleen if (!aliases) 11587e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1159dc098b35SAndi Kleen pmu = NULL; 1160dc098b35SAndi Kleen j = 0; 116142634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1162dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 116308e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 116408e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1165dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1166dc098b35SAndi Kleen 1167dc098b35SAndi Kleen if (event_glob != NULL && 116838d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 116938d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 117067bdc35fSAndi Kleen event_glob)) || 117167bdc35fSAndi Kleen (alias->topic && 117267bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1173dc098b35SAndi Kleen continue; 11747e4772dcSArnaldo Carvalho de Melo 117508e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 11767e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 11777e4772dcSArnaldo Carvalho de Melo 117808e60ed1SAndi Kleen aliases[j].name = name; 117908e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 118008e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 118108e60ed1SAndi Kleen sizeof(buf), 118208e60ed1SAndi Kleen pmu, alias); 118308e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 118408e60ed1SAndi Kleen if (!aliases[j].name) 11857e4772dcSArnaldo Carvalho de Melo goto out_enomem; 118608e60ed1SAndi Kleen 1187c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1188c8d6828aSSukadev Bhattiprolu alias->desc; 1189dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1190f2361024SAndi Kleen aliases[j].str = alias->str; 1191f2361024SAndi Kleen aliases[j].pmu = pmu->name; 1192dc098b35SAndi Kleen j++; 1193dc098b35SAndi Kleen } 1194fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1195fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 11967e4772dcSArnaldo Carvalho de Melo char *s; 11977e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 11987e4772dcSArnaldo Carvalho de Melo goto out_enomem; 119908e60ed1SAndi Kleen aliases[j].name = s; 120042634bc7SAdrian Hunter j++; 120142634bc7SAdrian Hunter } 120242634bc7SAdrian Hunter } 1203dc098b35SAndi Kleen len = j; 1204dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1205dc098b35SAndi Kleen for (j = 0; j < len; j++) { 120615b22ed3SAndi Kleen /* Skip duplicates */ 120715b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 120815b22ed3SAndi Kleen continue; 1209dc098b35SAndi Kleen if (name_only) { 121008e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1211dc098b35SAndi Kleen continue; 1212dc098b35SAndi Kleen } 12131c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 121408e60ed1SAndi Kleen if (numdesc++ == 0) 121508e60ed1SAndi Kleen printf("\n"); 1216dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1217dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1218dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1219dd5f1036SAndi Kleen aliases[j].topic); 1220dd5f1036SAndi Kleen topic = aliases[j].topic; 1221dd5f1036SAndi Kleen } 122208e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 122308e60ed1SAndi Kleen printf("%*s", 8, "["); 122408e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 122508e60ed1SAndi Kleen printf("]\n"); 1226f2361024SAndi Kleen if (verbose) 1227f2361024SAndi Kleen printf("%*s%s/%s/\n", 8, "", aliases[j].pmu, aliases[j].str); 122808e60ed1SAndi Kleen } else 122908e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1230dc098b35SAndi Kleen printed++; 1231dc098b35SAndi Kleen } 1232dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1233dc098b35SAndi Kleen printf("\n"); 12347e4772dcSArnaldo Carvalho de Melo out_free: 12357e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 123608e60ed1SAndi Kleen zfree(&aliases[j].name); 12377e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 12387e4772dcSArnaldo Carvalho de Melo return; 12397e4772dcSArnaldo Carvalho de Melo 12407e4772dcSArnaldo Carvalho de Melo out_enomem: 12417e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 12427e4772dcSArnaldo Carvalho de Melo if (aliases) 12437e4772dcSArnaldo Carvalho de Melo goto out_free; 1244dc098b35SAndi Kleen } 12454cabc3d1SAndi Kleen 12464cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 12474cabc3d1SAndi Kleen { 12484cabc3d1SAndi Kleen struct perf_pmu *pmu; 12494cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 12504cabc3d1SAndi Kleen 12514cabc3d1SAndi Kleen pmu = NULL; 12524cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 12534cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 12544cabc3d1SAndi Kleen continue; 12554cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 12564cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 12574cabc3d1SAndi Kleen return true; 12584cabc3d1SAndi Kleen } 12594cabc3d1SAndi Kleen return false; 12604cabc3d1SAndi Kleen } 12617d4bdab5SAdrian Hunter 12627d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 12637d4bdab5SAdrian Hunter { 12647d4bdab5SAdrian Hunter struct stat st; 12657d4bdab5SAdrian Hunter char path[PATH_MAX]; 12667d4bdab5SAdrian Hunter const char *sysfs; 12677d4bdab5SAdrian Hunter 12687d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 12697d4bdab5SAdrian Hunter if (!sysfs) 12707d4bdab5SAdrian Hunter return NULL; 12717d4bdab5SAdrian Hunter 12727d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 12737d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 12747d4bdab5SAdrian Hunter 12757d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 12767d4bdab5SAdrian Hunter return NULL; 12777d4bdab5SAdrian Hunter 12787d4bdab5SAdrian Hunter return fopen(path, "r"); 12797d4bdab5SAdrian Hunter } 12807d4bdab5SAdrian Hunter 12817d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 12827d4bdab5SAdrian Hunter ...) 12837d4bdab5SAdrian Hunter { 12847d4bdab5SAdrian Hunter va_list args; 12857d4bdab5SAdrian Hunter FILE *file; 12867d4bdab5SAdrian Hunter int ret = EOF; 12877d4bdab5SAdrian Hunter 12887d4bdab5SAdrian Hunter va_start(args, fmt); 12897d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 12907d4bdab5SAdrian Hunter if (file) { 12917d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 12927d4bdab5SAdrian Hunter fclose(file); 12937d4bdab5SAdrian Hunter } 12947d4bdab5SAdrian Hunter va_end(args); 12957d4bdab5SAdrian Hunter return ret; 12967d4bdab5SAdrian Hunter } 1297