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> 15cd82a32eSJiri Olsa #include "util.h" 16cd82a32eSJiri Olsa #include "pmu.h" 17cd82a32eSJiri Olsa #include "parse-events.h" 187ae92e74SYan, Zheng #include "cpumap.h" 19933f82ffSSukadev Bhattiprolu #include "header.h" 20933f82ffSSukadev Bhattiprolu #include "pmu-events/pmu-events.h" 2161eb2eb4SAndi Kleen #include "cache.h" 22a067558eSArnaldo Carvalho de Melo #include "string2.h" 23cd82a32eSJiri Olsa 24ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 25ab1bf653SArnaldo Carvalho de Melo char *name; 26ab1bf653SArnaldo Carvalho de Melo int value; 27ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 28ab1bf653SArnaldo Carvalho de Melo struct list_head list; 29ab1bf653SArnaldo Carvalho de Melo }; 30ab1bf653SArnaldo Carvalho de Melo 3150a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 3250a9667cSRobert Richter 33cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 34cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 35cd82a32eSJiri Olsa 36cd82a32eSJiri Olsa static LIST_HEAD(pmus); 37cd82a32eSJiri Olsa 38cd82a32eSJiri Olsa /* 39cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 40cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 41cd82a32eSJiri Olsa */ 42cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 43cd82a32eSJiri Olsa { 44cd82a32eSJiri Olsa struct dirent *evt_ent; 45cd82a32eSJiri Olsa DIR *format_dir; 46cd82a32eSJiri Olsa int ret = 0; 47cd82a32eSJiri Olsa 48cd82a32eSJiri Olsa format_dir = opendir(dir); 49cd82a32eSJiri Olsa if (!format_dir) 50cd82a32eSJiri Olsa return -EINVAL; 51cd82a32eSJiri Olsa 52cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 53cd82a32eSJiri Olsa char path[PATH_MAX]; 54cd82a32eSJiri Olsa char *name = evt_ent->d_name; 55cd82a32eSJiri Olsa FILE *file; 56cd82a32eSJiri Olsa 57cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 58cd82a32eSJiri Olsa continue; 59cd82a32eSJiri Olsa 60cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 61cd82a32eSJiri Olsa 62cd82a32eSJiri Olsa ret = -EINVAL; 63cd82a32eSJiri Olsa file = fopen(path, "r"); 64cd82a32eSJiri Olsa if (!file) 65cd82a32eSJiri Olsa break; 66cd82a32eSJiri Olsa 67cd82a32eSJiri Olsa perf_pmu_in = file; 68cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 69cd82a32eSJiri Olsa fclose(file); 70cd82a32eSJiri Olsa } 71cd82a32eSJiri Olsa 72cd82a32eSJiri Olsa closedir(format_dir); 73cd82a32eSJiri Olsa return ret; 74cd82a32eSJiri Olsa } 75cd82a32eSJiri Olsa 76cd82a32eSJiri Olsa /* 77cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 78cd82a32eSJiri Olsa * located at: 79cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 80cd82a32eSJiri Olsa */ 81b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 82cd82a32eSJiri Olsa { 83cd82a32eSJiri Olsa struct stat st; 84cd82a32eSJiri Olsa char path[PATH_MAX]; 85cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 86cd82a32eSJiri Olsa 87cd82a32eSJiri Olsa if (!sysfs) 88cd82a32eSJiri Olsa return -1; 89cd82a32eSJiri Olsa 90cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9150a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 92cd82a32eSJiri Olsa 93cd82a32eSJiri Olsa if (stat(path, &st) < 0) 949bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 95cd82a32eSJiri Olsa 96cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 97cd82a32eSJiri Olsa return -1; 98cd82a32eSJiri Olsa 99cd82a32eSJiri Olsa return 0; 100cd82a32eSJiri Olsa } 101cd82a32eSJiri Olsa 102d02fc6bcSAndi Kleen static int convert_scale(const char *scale, char **end, double *sval) 103d02fc6bcSAndi Kleen { 104d02fc6bcSAndi Kleen char *lc; 105d02fc6bcSAndi Kleen int ret = 0; 106d02fc6bcSAndi Kleen 107d02fc6bcSAndi Kleen /* 108d02fc6bcSAndi Kleen * save current locale 109d02fc6bcSAndi Kleen */ 110d02fc6bcSAndi Kleen lc = setlocale(LC_NUMERIC, NULL); 111d02fc6bcSAndi Kleen 112d02fc6bcSAndi Kleen /* 113d02fc6bcSAndi Kleen * The lc string may be allocated in static storage, 114d02fc6bcSAndi Kleen * so get a dynamic copy to make it survive setlocale 115d02fc6bcSAndi Kleen * call below. 116d02fc6bcSAndi Kleen */ 117d02fc6bcSAndi Kleen lc = strdup(lc); 118d02fc6bcSAndi Kleen if (!lc) { 119d02fc6bcSAndi Kleen ret = -ENOMEM; 120d02fc6bcSAndi Kleen goto out; 121d02fc6bcSAndi Kleen } 122d02fc6bcSAndi Kleen 123d02fc6bcSAndi Kleen /* 124d02fc6bcSAndi Kleen * force to C locale to ensure kernel 125d02fc6bcSAndi Kleen * scale string is converted correctly. 126d02fc6bcSAndi Kleen * kernel uses default C locale. 127d02fc6bcSAndi Kleen */ 128d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, "C"); 129d02fc6bcSAndi Kleen 130d02fc6bcSAndi Kleen *sval = strtod(scale, end); 131d02fc6bcSAndi Kleen 132d02fc6bcSAndi Kleen out: 133d02fc6bcSAndi Kleen /* restore locale */ 134d02fc6bcSAndi Kleen setlocale(LC_NUMERIC, lc); 135d02fc6bcSAndi Kleen free(lc); 136d02fc6bcSAndi Kleen return ret; 137d02fc6bcSAndi Kleen } 138d02fc6bcSAndi Kleen 139410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 140410136f5SStephane Eranian { 141410136f5SStephane Eranian struct stat st; 142410136f5SStephane Eranian ssize_t sret; 143410136f5SStephane Eranian char scale[128]; 144410136f5SStephane Eranian int fd, ret = -1; 145410136f5SStephane Eranian char path[PATH_MAX]; 146410136f5SStephane Eranian 147410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 148410136f5SStephane Eranian 149410136f5SStephane Eranian fd = open(path, O_RDONLY); 150410136f5SStephane Eranian if (fd == -1) 151410136f5SStephane Eranian return -1; 152410136f5SStephane Eranian 153410136f5SStephane Eranian if (fstat(fd, &st) < 0) 154410136f5SStephane Eranian goto error; 155410136f5SStephane Eranian 156410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 157410136f5SStephane Eranian if (sret < 0) 158410136f5SStephane Eranian goto error; 159410136f5SStephane Eranian 1609ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1619ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1629ecae065SMadhavan Srinivasan else 163410136f5SStephane Eranian scale[sret] = '\0'; 1649ecae065SMadhavan Srinivasan 165d02fc6bcSAndi Kleen ret = convert_scale(scale, NULL, &alias->scale); 166410136f5SStephane Eranian error: 167410136f5SStephane Eranian close(fd); 168410136f5SStephane Eranian return ret; 169410136f5SStephane Eranian } 170410136f5SStephane Eranian 171410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 172410136f5SStephane Eranian { 173410136f5SStephane Eranian char path[PATH_MAX]; 174410136f5SStephane Eranian ssize_t sret; 175410136f5SStephane Eranian int fd; 176410136f5SStephane Eranian 177410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 178410136f5SStephane Eranian 179410136f5SStephane Eranian fd = open(path, O_RDONLY); 180410136f5SStephane Eranian if (fd == -1) 181410136f5SStephane Eranian return -1; 182410136f5SStephane Eranian 183410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 184410136f5SStephane Eranian if (sret < 0) 185410136f5SStephane Eranian goto error; 186410136f5SStephane Eranian 187410136f5SStephane Eranian close(fd); 188410136f5SStephane Eranian 1899ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1909ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1919ecae065SMadhavan Srinivasan else 192410136f5SStephane Eranian alias->unit[sret] = '\0'; 193410136f5SStephane Eranian 194410136f5SStephane Eranian return 0; 195410136f5SStephane Eranian error: 196410136f5SStephane Eranian close(fd); 197410136f5SStephane Eranian alias->unit[0] = '\0'; 198410136f5SStephane Eranian return -1; 199410136f5SStephane Eranian } 200410136f5SStephane Eranian 201044330c1SMatt Fleming static int 202044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 203044330c1SMatt Fleming { 204044330c1SMatt Fleming char path[PATH_MAX]; 205044330c1SMatt Fleming int fd; 206044330c1SMatt Fleming 207044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 208044330c1SMatt Fleming 209044330c1SMatt Fleming fd = open(path, O_RDONLY); 210044330c1SMatt Fleming if (fd == -1) 211044330c1SMatt Fleming return -1; 212044330c1SMatt Fleming 213044330c1SMatt Fleming close(fd); 214044330c1SMatt Fleming 215044330c1SMatt Fleming alias->per_pkg = true; 216044330c1SMatt Fleming return 0; 217044330c1SMatt Fleming } 218044330c1SMatt Fleming 2191d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2201d9e446bSJiri Olsa char *dir, char *name) 2211d9e446bSJiri Olsa { 2221d9e446bSJiri Olsa char path[PATH_MAX]; 2231d9e446bSJiri Olsa int fd; 2241d9e446bSJiri Olsa 2251d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2261d9e446bSJiri Olsa 2271d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2281d9e446bSJiri Olsa if (fd == -1) 2291d9e446bSJiri Olsa return -1; 2301d9e446bSJiri Olsa 2311d9e446bSJiri Olsa alias->snapshot = true; 2321d9e446bSJiri Olsa close(fd); 2331d9e446bSJiri Olsa return 0; 2341d9e446bSJiri Olsa } 2351d9e446bSJiri Olsa 23670c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 237fedb2b51SAndi Kleen char *desc, char *val, 238fedb2b51SAndi Kleen char *long_desc, char *topic, 23900636c3bSAndi Kleen char *unit, char *perpkg, 24096284814SAndi Kleen char *metric_expr, 24196284814SAndi Kleen char *metric_name) 242a6146d50SZheng Yan { 2435c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 244a6146d50SZheng Yan int ret; 245fedb2b51SAndi Kleen int num; 246a6146d50SZheng Yan 247a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 248a6146d50SZheng Yan if (!alias) 249a6146d50SZheng Yan return -ENOMEM; 250a6146d50SZheng Yan 251a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 252410136f5SStephane Eranian alias->scale = 1.0; 253410136f5SStephane Eranian alias->unit[0] = '\0'; 254044330c1SMatt Fleming alias->per_pkg = false; 25584530920SStephane Eranian alias->snapshot = false; 256410136f5SStephane Eranian 25770c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 258a6146d50SZheng Yan if (ret) { 25970c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 260a6146d50SZheng Yan free(alias); 261a6146d50SZheng Yan return ret; 262a6146d50SZheng Yan } 263a6146d50SZheng Yan 264a6146d50SZheng Yan alias->name = strdup(name); 26570c646e0SSukadev Bhattiprolu if (dir) { 266410136f5SStephane Eranian /* 267410136f5SStephane Eranian * load unit name and scale if available 268410136f5SStephane Eranian */ 269410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 270410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 271044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2721d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 27370c646e0SSukadev Bhattiprolu } 274410136f5SStephane Eranian 27500636c3bSAndi Kleen alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL; 27696284814SAndi Kleen alias->metric_name = metric_name ? strdup(metric_name): NULL; 27708e60ed1SAndi Kleen alias->desc = desc ? strdup(desc) : NULL; 278c8d6828aSSukadev Bhattiprolu alias->long_desc = long_desc ? strdup(long_desc) : 279c8d6828aSSukadev Bhattiprolu desc ? strdup(desc) : NULL; 280dd5f1036SAndi Kleen alias->topic = topic ? strdup(topic) : NULL; 281fedb2b51SAndi Kleen if (unit) { 282fedb2b51SAndi Kleen if (convert_scale(unit, &unit, &alias->scale) < 0) 283fedb2b51SAndi Kleen return -1; 284fedb2b51SAndi Kleen snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 285fedb2b51SAndi Kleen } 286fedb2b51SAndi Kleen alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 287f2361024SAndi Kleen alias->str = strdup(val); 288f2361024SAndi Kleen 289a6146d50SZheng Yan list_add_tail(&alias->list, list); 290410136f5SStephane Eranian 291a6146d50SZheng Yan return 0; 292a6146d50SZheng Yan } 293a6146d50SZheng Yan 29470c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 29570c646e0SSukadev Bhattiprolu { 29670c646e0SSukadev Bhattiprolu char buf[256]; 29770c646e0SSukadev Bhattiprolu int ret; 29870c646e0SSukadev Bhattiprolu 29970c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 30070c646e0SSukadev Bhattiprolu if (ret == 0) 30170c646e0SSukadev Bhattiprolu return -EINVAL; 30270c646e0SSukadev Bhattiprolu 30370c646e0SSukadev Bhattiprolu buf[ret] = 0; 30470c646e0SSukadev Bhattiprolu 305fedb2b51SAndi Kleen return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 30696284814SAndi Kleen NULL, NULL, NULL); 30770c646e0SSukadev Bhattiprolu } 30870c646e0SSukadev Bhattiprolu 30946441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 31046441bdcSMatt Fleming { 31146441bdcSMatt Fleming size_t len; 31246441bdcSMatt Fleming 31346441bdcSMatt Fleming len = strlen(name); 31446441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 31546441bdcSMatt Fleming return true; 31646441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 31746441bdcSMatt Fleming return true; 318044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 319044330c1SMatt Fleming return true; 3201d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 3211d9e446bSJiri Olsa return true; 32246441bdcSMatt Fleming 32346441bdcSMatt Fleming return false; 32446441bdcSMatt Fleming } 32546441bdcSMatt Fleming 326a6146d50SZheng Yan /* 327a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 328a6146d50SZheng Yan * specified in 'dir' parameter. 329a6146d50SZheng Yan */ 330a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 331a6146d50SZheng Yan { 332a6146d50SZheng Yan struct dirent *evt_ent; 333a6146d50SZheng Yan DIR *event_dir; 334a6146d50SZheng Yan 335a6146d50SZheng Yan event_dir = opendir(dir); 336a6146d50SZheng Yan if (!event_dir) 337a6146d50SZheng Yan return -EINVAL; 338a6146d50SZheng Yan 339940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 340a6146d50SZheng Yan char path[PATH_MAX]; 341a6146d50SZheng Yan char *name = evt_ent->d_name; 342a6146d50SZheng Yan FILE *file; 343a6146d50SZheng Yan 344a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 345a6146d50SZheng Yan continue; 346a6146d50SZheng Yan 347410136f5SStephane Eranian /* 34846441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 349410136f5SStephane Eranian */ 35046441bdcSMatt Fleming if (pmu_alias_info_file(name)) 351410136f5SStephane Eranian continue; 352410136f5SStephane Eranian 353a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 354a6146d50SZheng Yan 355a6146d50SZheng Yan file = fopen(path, "r"); 356940db6dcSAndi Kleen if (!file) { 357940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 358940db6dcSAndi Kleen continue; 359940db6dcSAndi Kleen } 360410136f5SStephane Eranian 361940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 362940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 363a6146d50SZheng Yan fclose(file); 364a6146d50SZheng Yan } 365a6146d50SZheng Yan 366a6146d50SZheng Yan closedir(event_dir); 367940db6dcSAndi Kleen return 0; 368a6146d50SZheng Yan } 369a6146d50SZheng Yan 370a6146d50SZheng Yan /* 371a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 372a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 373a6146d50SZheng Yan */ 374b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 375a6146d50SZheng Yan { 376a6146d50SZheng Yan struct stat st; 377a6146d50SZheng Yan char path[PATH_MAX]; 378cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 379a6146d50SZheng Yan 380a6146d50SZheng Yan if (!sysfs) 381a6146d50SZheng Yan return -1; 382a6146d50SZheng Yan 383a6146d50SZheng Yan snprintf(path, PATH_MAX, 384a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 385a6146d50SZheng Yan 386a6146d50SZheng Yan if (stat(path, &st) < 0) 3873fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 388a6146d50SZheng Yan 389a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 390a6146d50SZheng Yan return -1; 391a6146d50SZheng Yan 392a6146d50SZheng Yan return 0; 393a6146d50SZheng Yan } 394a6146d50SZheng Yan 3955c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 396a6146d50SZheng Yan struct list_head *terms) 397a6146d50SZheng Yan { 3987c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 399a6146d50SZheng Yan LIST_HEAD(list); 400a6146d50SZheng Yan int ret; 401a6146d50SZheng Yan 402a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 4037c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 404a6146d50SZheng Yan if (ret) { 405682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 406a6146d50SZheng Yan return ret; 407a6146d50SZheng Yan } 408c2f1ceadSAndi Kleen /* 409c2f1ceadSAndi Kleen * Weak terms don't override command line options, 410c2f1ceadSAndi Kleen * which we don't want for implicit terms in aliases. 411c2f1ceadSAndi Kleen */ 412c2f1ceadSAndi Kleen cloned->weak = true; 4137c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 414a6146d50SZheng Yan } 415a6146d50SZheng Yan list_splice(&list, terms); 416a6146d50SZheng Yan return 0; 417a6146d50SZheng Yan } 418a6146d50SZheng Yan 419cd82a32eSJiri Olsa /* 420cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 421cd82a32eSJiri Olsa * located at: 422cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 423cd82a32eSJiri Olsa */ 424b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 425cd82a32eSJiri Olsa { 426cd82a32eSJiri Olsa struct stat st; 427cd82a32eSJiri Olsa char path[PATH_MAX]; 428cd82a32eSJiri Olsa FILE *file; 429cd82a32eSJiri Olsa int ret = 0; 430cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 431cd82a32eSJiri Olsa 432cd82a32eSJiri Olsa if (!sysfs) 433cd82a32eSJiri Olsa return -1; 434cd82a32eSJiri Olsa 435cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 43650a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 437cd82a32eSJiri Olsa 438cd82a32eSJiri Olsa if (stat(path, &st) < 0) 439cd82a32eSJiri Olsa return -1; 440cd82a32eSJiri Olsa 441cd82a32eSJiri Olsa file = fopen(path, "r"); 442cd82a32eSJiri Olsa if (!file) 443cd82a32eSJiri Olsa return -EINVAL; 444cd82a32eSJiri Olsa 445cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 446cd82a32eSJiri Olsa ret = -1; 447cd82a32eSJiri Olsa 448cd82a32eSJiri Olsa fclose(file); 449cd82a32eSJiri Olsa return ret; 450cd82a32eSJiri Olsa } 451cd82a32eSJiri Olsa 45250a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 45350a9667cSRobert Richter static void pmu_read_sysfs(void) 45450a9667cSRobert Richter { 45550a9667cSRobert Richter char path[PATH_MAX]; 45650a9667cSRobert Richter DIR *dir; 45750a9667cSRobert Richter struct dirent *dent; 458cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 45950a9667cSRobert Richter 46050a9667cSRobert Richter if (!sysfs) 46150a9667cSRobert Richter return; 46250a9667cSRobert Richter 46350a9667cSRobert Richter snprintf(path, PATH_MAX, 46450a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 46550a9667cSRobert Richter 46650a9667cSRobert Richter dir = opendir(path); 46750a9667cSRobert Richter if (!dir) 46850a9667cSRobert Richter return; 46950a9667cSRobert Richter 47050a9667cSRobert Richter while ((dent = readdir(dir))) { 47150a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 47250a9667cSRobert Richter continue; 47350a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 47450a9667cSRobert Richter perf_pmu__find(dent->d_name); 47550a9667cSRobert Richter } 47650a9667cSRobert Richter 47750a9667cSRobert Richter closedir(dir); 47850a9667cSRobert Richter } 47950a9667cSRobert Richter 48066ec1191SMark Rutland static struct cpu_map *__pmu_cpumask(const char *path) 48166ec1191SMark Rutland { 48266ec1191SMark Rutland FILE *file; 48366ec1191SMark Rutland struct cpu_map *cpus; 48466ec1191SMark Rutland 48566ec1191SMark Rutland file = fopen(path, "r"); 48666ec1191SMark Rutland if (!file) 48766ec1191SMark Rutland return NULL; 48866ec1191SMark Rutland 48966ec1191SMark Rutland cpus = cpu_map__read(file); 49066ec1191SMark Rutland fclose(file); 49166ec1191SMark Rutland return cpus; 49266ec1191SMark Rutland } 49366ec1191SMark Rutland 49466ec1191SMark Rutland /* 49566ec1191SMark Rutland * Uncore PMUs have a "cpumask" file under sysfs. CPU PMUs (e.g. on arm/arm64) 49666ec1191SMark Rutland * may have a "cpus" file. 49766ec1191SMark Rutland */ 49866ec1191SMark Rutland #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" 49966ec1191SMark Rutland #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" 50066ec1191SMark Rutland 501b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 5027ae92e74SYan, Zheng { 5037ae92e74SYan, Zheng char path[PATH_MAX]; 5047ae92e74SYan, Zheng struct cpu_map *cpus; 505cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 5067e3fcffeSMark Rutland const char *templates[] = { 50766ec1191SMark Rutland CPUS_TEMPLATE_UNCORE, 50866ec1191SMark Rutland CPUS_TEMPLATE_CPU, 5097e3fcffeSMark Rutland NULL 5107e3fcffeSMark Rutland }; 5117e3fcffeSMark Rutland const char **template; 5127ae92e74SYan, Zheng 5137ae92e74SYan, Zheng if (!sysfs) 5147ae92e74SYan, Zheng return NULL; 5157ae92e74SYan, Zheng 5167e3fcffeSMark Rutland for (template = templates; *template; template++) { 5177e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 51866ec1191SMark Rutland cpus = __pmu_cpumask(path); 51966ec1191SMark Rutland if (cpus) 52066ec1191SMark Rutland return cpus; 5217e3fcffeSMark Rutland } 5227ae92e74SYan, Zheng 5237ae92e74SYan, Zheng return NULL; 52466ec1191SMark Rutland } 5257ae92e74SYan, Zheng 52666ec1191SMark Rutland static bool pmu_is_uncore(const char *name) 52766ec1191SMark Rutland { 52866ec1191SMark Rutland char path[PATH_MAX]; 52966ec1191SMark Rutland struct cpu_map *cpus; 53066ec1191SMark Rutland const char *sysfs = sysfs__mountpoint(); 5317ae92e74SYan, Zheng 53266ec1191SMark Rutland snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); 53366ec1191SMark Rutland cpus = __pmu_cpumask(path); 53466ec1191SMark Rutland cpu_map__put(cpus); 53566ec1191SMark Rutland 53666ec1191SMark Rutland return !!cpus; 5377ae92e74SYan, Zheng } 5387ae92e74SYan, Zheng 539933f82ffSSukadev Bhattiprolu /* 540933f82ffSSukadev Bhattiprolu * Return the CPU id as a raw string. 541933f82ffSSukadev Bhattiprolu * 542933f82ffSSukadev Bhattiprolu * Each architecture should provide a more precise id string that 543933f82ffSSukadev Bhattiprolu * can be use to match the architecture's "mapfile". 544933f82ffSSukadev Bhattiprolu */ 54554e32dc0SGanapatrao Kulkarni char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 546933f82ffSSukadev Bhattiprolu { 547933f82ffSSukadev Bhattiprolu return NULL; 548933f82ffSSukadev Bhattiprolu } 549933f82ffSSukadev Bhattiprolu 55054e32dc0SGanapatrao Kulkarni static char *perf_pmu__getcpuid(struct perf_pmu *pmu) 551d77ade9fSAndi Kleen { 552d77ade9fSAndi Kleen char *cpuid; 553d77ade9fSAndi Kleen static bool printed; 554d77ade9fSAndi Kleen 555d77ade9fSAndi Kleen cpuid = getenv("PERF_CPUID"); 556d77ade9fSAndi Kleen if (cpuid) 557d77ade9fSAndi Kleen cpuid = strdup(cpuid); 558d77ade9fSAndi Kleen if (!cpuid) 55954e32dc0SGanapatrao Kulkarni cpuid = get_cpuid_str(pmu); 560d77ade9fSAndi Kleen if (!cpuid) 561d77ade9fSAndi Kleen return NULL; 562d77ade9fSAndi Kleen 563d77ade9fSAndi Kleen if (!printed) { 564d77ade9fSAndi Kleen pr_debug("Using CPUID %s\n", cpuid); 565d77ade9fSAndi Kleen printed = true; 566d77ade9fSAndi Kleen } 567d77ade9fSAndi Kleen return cpuid; 568d77ade9fSAndi Kleen } 569d77ade9fSAndi Kleen 57054e32dc0SGanapatrao Kulkarni struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu) 571d77ade9fSAndi Kleen { 572d77ade9fSAndi Kleen struct pmu_events_map *map; 57354e32dc0SGanapatrao Kulkarni char *cpuid = perf_pmu__getcpuid(pmu); 574d77ade9fSAndi Kleen int i; 575d77ade9fSAndi Kleen 576d77ade9fSAndi Kleen i = 0; 577d77ade9fSAndi Kleen for (;;) { 578d77ade9fSAndi Kleen map = &pmu_events_map[i++]; 579d77ade9fSAndi Kleen if (!map->table) { 580d77ade9fSAndi Kleen map = NULL; 581d77ade9fSAndi Kleen break; 582d77ade9fSAndi Kleen } 583d77ade9fSAndi Kleen 584d77ade9fSAndi Kleen if (!strcmp(map->cpuid, cpuid)) 585d77ade9fSAndi Kleen break; 586d77ade9fSAndi Kleen } 587d77ade9fSAndi Kleen free(cpuid); 588d77ade9fSAndi Kleen return map; 589d77ade9fSAndi Kleen } 590d77ade9fSAndi Kleen 591933f82ffSSukadev Bhattiprolu /* 592933f82ffSSukadev Bhattiprolu * From the pmu_events_map, find the table of PMU events that corresponds 593933f82ffSSukadev Bhattiprolu * to the current running CPU. Then, add all PMU events from that table 594933f82ffSSukadev Bhattiprolu * as aliases. 595933f82ffSSukadev Bhattiprolu */ 59654e32dc0SGanapatrao Kulkarni static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu) 597933f82ffSSukadev Bhattiprolu { 598933f82ffSSukadev Bhattiprolu int i; 599933f82ffSSukadev Bhattiprolu struct pmu_events_map *map; 600933f82ffSSukadev Bhattiprolu struct pmu_event *pe; 60154e32dc0SGanapatrao Kulkarni const char *name = pmu->name; 602933f82ffSSukadev Bhattiprolu 60354e32dc0SGanapatrao Kulkarni map = perf_pmu__find_map(pmu); 604d77ade9fSAndi Kleen if (!map) 605933f82ffSSukadev Bhattiprolu return; 606933f82ffSSukadev Bhattiprolu 607933f82ffSSukadev Bhattiprolu /* 608933f82ffSSukadev Bhattiprolu * Found a matching PMU events table. Create aliases 609933f82ffSSukadev Bhattiprolu */ 610933f82ffSSukadev Bhattiprolu i = 0; 611933f82ffSSukadev Bhattiprolu while (1) { 612fedb2b51SAndi Kleen const char *pname; 613fedb2b51SAndi Kleen 614933f82ffSSukadev Bhattiprolu pe = &map->table[i++]; 615b18f3e36SAndi Kleen if (!pe->name) { 616b18f3e36SAndi Kleen if (pe->metric_group || pe->metric_name) 617b18f3e36SAndi Kleen continue; 618933f82ffSSukadev Bhattiprolu break; 619b18f3e36SAndi Kleen } 620933f82ffSSukadev Bhattiprolu 621fedb2b51SAndi Kleen pname = pe->pmu ? pe->pmu : "cpu"; 622fedb2b51SAndi Kleen if (strncmp(pname, name, strlen(pname))) 623fedb2b51SAndi Kleen continue; 624fedb2b51SAndi Kleen 625933f82ffSSukadev Bhattiprolu /* need type casts to override 'const' */ 626933f82ffSSukadev Bhattiprolu __perf_pmu__new_alias(head, NULL, (char *)pe->name, 627c8d6828aSSukadev Bhattiprolu (char *)pe->desc, (char *)pe->event, 628fedb2b51SAndi Kleen (char *)pe->long_desc, (char *)pe->topic, 62900636c3bSAndi Kleen (char *)pe->unit, (char *)pe->perpkg, 63096284814SAndi Kleen (char *)pe->metric_expr, 63196284814SAndi Kleen (char *)pe->metric_name); 632933f82ffSSukadev Bhattiprolu } 633933f82ffSSukadev Bhattiprolu } 634933f82ffSSukadev Bhattiprolu 635c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 636dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 637dc0a6202SAdrian Hunter { 638dc0a6202SAdrian Hunter return NULL; 639dc0a6202SAdrian Hunter } 640dc0a6202SAdrian Hunter 641b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 642cd82a32eSJiri Olsa { 643cd82a32eSJiri Olsa struct perf_pmu *pmu; 644cd82a32eSJiri Olsa LIST_HEAD(format); 645a6146d50SZheng Yan LIST_HEAD(aliases); 646cd82a32eSJiri Olsa __u32 type; 647cd82a32eSJiri Olsa 648cd82a32eSJiri Olsa /* 649cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 650cd82a32eSJiri Olsa * type value and format definitions. Load both right 651cd82a32eSJiri Olsa * now. 652cd82a32eSJiri Olsa */ 653cd82a32eSJiri Olsa if (pmu_format(name, &format)) 654cd82a32eSJiri Olsa return NULL; 655cd82a32eSJiri Olsa 65615b22ed3SAndi Kleen /* 65715b22ed3SAndi Kleen * Check the type first to avoid unnecessary work. 65815b22ed3SAndi Kleen */ 65915b22ed3SAndi Kleen if (pmu_type(name, &type)) 66015b22ed3SAndi Kleen return NULL; 66115b22ed3SAndi Kleen 6623fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 6633fded963SJiri Olsa return NULL; 6643fded963SJiri Olsa 665cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 666cd82a32eSJiri Olsa if (!pmu) 667cd82a32eSJiri Olsa return NULL; 668cd82a32eSJiri Olsa 6697ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 67054e32dc0SGanapatrao Kulkarni pmu->name = strdup(name); 67154e32dc0SGanapatrao Kulkarni pmu->type = type; 67266ec1191SMark Rutland pmu->is_uncore = pmu_is_uncore(name); 67354e32dc0SGanapatrao Kulkarni pmu_add_cpu_aliases(&aliases, pmu); 67466ec1191SMark Rutland 675cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 676a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 677cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 678a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 6799bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 680dc0a6202SAdrian Hunter 681dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 682dc0a6202SAdrian Hunter 683cd82a32eSJiri Olsa return pmu; 684cd82a32eSJiri Olsa } 685cd82a32eSJiri Olsa 686b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 687cd82a32eSJiri Olsa { 688cd82a32eSJiri Olsa struct perf_pmu *pmu; 689cd82a32eSJiri Olsa 690cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 691cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 692cd82a32eSJiri Olsa return pmu; 693cd82a32eSJiri Olsa 694cd82a32eSJiri Olsa return NULL; 695cd82a32eSJiri Olsa } 696cd82a32eSJiri Olsa 69750a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 69850a9667cSRobert Richter { 69950a9667cSRobert Richter /* 70050a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 70150a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 70250a9667cSRobert Richter */ 70350a9667cSRobert Richter if (!pmu) { 70450a9667cSRobert Richter pmu_read_sysfs(); 70550a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 70650a9667cSRobert Richter } 70750a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 70850a9667cSRobert Richter return pmu; 70950a9667cSRobert Richter return NULL; 71050a9667cSRobert Richter } 71150a9667cSRobert Richter 712b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 713cd82a32eSJiri Olsa { 714cd82a32eSJiri Olsa struct perf_pmu *pmu; 715cd82a32eSJiri Olsa 716cd82a32eSJiri Olsa /* 717cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 718cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 719cd82a32eSJiri Olsa * the pmu format definitions. 720cd82a32eSJiri Olsa */ 721cd82a32eSJiri Olsa pmu = pmu_find(name); 722cd82a32eSJiri Olsa if (pmu) 723cd82a32eSJiri Olsa return pmu; 724cd82a32eSJiri Olsa 725cd82a32eSJiri Olsa return pmu_lookup(name); 726cd82a32eSJiri Olsa } 727cd82a32eSJiri Olsa 7285c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 72909ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 730cd82a32eSJiri Olsa { 7315c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 732cd82a32eSJiri Olsa 733cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 734cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 735cd82a32eSJiri Olsa return format; 736cd82a32eSJiri Olsa 737cd82a32eSJiri Olsa return NULL; 738cd82a32eSJiri Olsa } 739cd82a32eSJiri Olsa 74009ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 74109ff6071SAdrian Hunter { 74209ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 74309ff6071SAdrian Hunter __u64 bits = 0; 74409ff6071SAdrian Hunter int fbit; 74509ff6071SAdrian Hunter 74609ff6071SAdrian Hunter if (!format) 74709ff6071SAdrian Hunter return 0; 74809ff6071SAdrian Hunter 74909ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 75009ff6071SAdrian Hunter bits |= 1ULL << fbit; 75109ff6071SAdrian Hunter 75209ff6071SAdrian Hunter return bits; 75309ff6071SAdrian Hunter } 75409ff6071SAdrian Hunter 755cd82a32eSJiri Olsa /* 756dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 757cd82a32eSJiri Olsa * and unformated value (value parameter). 758cd82a32eSJiri Olsa */ 759dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 760dc0a6202SAdrian Hunter bool zero) 761cd82a32eSJiri Olsa { 762cd82a32eSJiri Olsa unsigned long fbit, vbit; 763cd82a32eSJiri Olsa 764cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 765cd82a32eSJiri Olsa 766cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 767cd82a32eSJiri Olsa continue; 768cd82a32eSJiri Olsa 769dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 770dc0a6202SAdrian Hunter *v |= (1llu << fbit); 771dc0a6202SAdrian Hunter else if (zero) 772dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 773cd82a32eSJiri Olsa } 774cd82a32eSJiri Olsa } 775cd82a32eSJiri Olsa 7760efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 7770efe6b67SAdrian Hunter { 778ac0e2cd5SKan Liang __u64 w = 0; 779ac0e2cd5SKan Liang int fbit; 7800efe6b67SAdrian Hunter 781ac0e2cd5SKan Liang for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) 782ac0e2cd5SKan Liang w |= (1ULL << fbit); 783ac0e2cd5SKan Liang 784ac0e2cd5SKan Liang return w; 7850efe6b67SAdrian Hunter } 7860efe6b67SAdrian Hunter 787cd82a32eSJiri Olsa /* 788688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 789688d4dfcSCody P Schafer * in the remaining terms. 790688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 791688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 792688d4dfcSCody P Schafer * in a config string) later on in the term list. 793688d4dfcSCody P Schafer */ 794688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 795688d4dfcSCody P Schafer struct list_head *head_terms, 796688d4dfcSCody P Schafer __u64 *value) 797688d4dfcSCody P Schafer { 798688d4dfcSCody P Schafer struct parse_events_term *t; 799688d4dfcSCody P Schafer 800688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 801688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 802688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 803688d4dfcSCody P Schafer t->used = true; 804688d4dfcSCody P Schafer *value = t->val.num; 805688d4dfcSCody P Schafer return 0; 806688d4dfcSCody P Schafer } 807688d4dfcSCody P Schafer } 808688d4dfcSCody P Schafer } 809688d4dfcSCody P Schafer 810bb963e16SNamhyung Kim if (verbose > 0) 811688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 812688d4dfcSCody P Schafer 813688d4dfcSCody P Schafer return -1; 814688d4dfcSCody P Schafer } 815688d4dfcSCody P Schafer 816ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 817e64b020bSJiri Olsa { 818e64b020bSJiri Olsa struct perf_pmu_format *format; 81911db4e29SMasami Hiramatsu char *str = NULL; 82011db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 821e64b020bSJiri Olsa unsigned i = 0; 822e64b020bSJiri Olsa 823ffeb883eSHe Kuang if (!formats) 824e64b020bSJiri Olsa return NULL; 825e64b020bSJiri Olsa 826e64b020bSJiri Olsa /* sysfs exported terms */ 827ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 82811db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 82911db4e29SMasami Hiramatsu goto error; 830e64b020bSJiri Olsa 831ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 83211db4e29SMasami Hiramatsu error: 833ffeb883eSHe Kuang strbuf_release(&buf); 834e64b020bSJiri Olsa 835e64b020bSJiri Olsa return str; 836e64b020bSJiri Olsa } 837e64b020bSJiri Olsa 838688d4dfcSCody P Schafer /* 839cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 84088aca8d9SCody P Schafer * user input data - term parameter. 841cd82a32eSJiri Olsa */ 842cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 843cd82a32eSJiri Olsa struct perf_event_attr *attr, 844dc0a6202SAdrian Hunter struct parse_events_term *term, 845688d4dfcSCody P Schafer struct list_head *head_terms, 846e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 847cd82a32eSJiri Olsa { 8485c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 849cd82a32eSJiri Olsa __u64 *vp; 8500efe6b67SAdrian Hunter __u64 val, max_val; 851cd82a32eSJiri Olsa 852cd82a32eSJiri Olsa /* 853688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 854688d4dfcSCody P Schafer * skip it in normal eval. 855688d4dfcSCody P Schafer */ 856688d4dfcSCody P Schafer if (term->used) 857688d4dfcSCody P Schafer return 0; 858688d4dfcSCody P Schafer 859688d4dfcSCody P Schafer /* 860cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 861cd82a32eSJiri Olsa * to be done for them. 862cd82a32eSJiri Olsa */ 863cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 864cd82a32eSJiri Olsa return 0; 865cd82a32eSJiri Olsa 866cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 867688d4dfcSCody P Schafer if (!format) { 868bb963e16SNamhyung Kim if (verbose > 0) 869688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 870e64b020bSJiri Olsa if (err) { 871ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 872ffeb883eSHe Kuang 873e64b020bSJiri Olsa err->idx = term->err_term; 874e64b020bSJiri Olsa err->str = strdup("unknown term"); 875ffeb883eSHe Kuang err->help = parse_events_formats_error_string(pmu_term); 876ffeb883eSHe Kuang free(pmu_term); 877e64b020bSJiri Olsa } 878cd82a32eSJiri Olsa return -EINVAL; 879688d4dfcSCody P Schafer } 880cd82a32eSJiri Olsa 881cd82a32eSJiri Olsa switch (format->value) { 882cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 883cd82a32eSJiri Olsa vp = &attr->config; 884cd82a32eSJiri Olsa break; 885cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 886cd82a32eSJiri Olsa vp = &attr->config1; 887cd82a32eSJiri Olsa break; 888cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 889cd82a32eSJiri Olsa vp = &attr->config2; 890cd82a32eSJiri Olsa break; 891cd82a32eSJiri Olsa default: 892cd82a32eSJiri Olsa return -EINVAL; 893cd82a32eSJiri Olsa } 894cd82a32eSJiri Olsa 89516fa7e82SJiri Olsa /* 896688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 897688d4dfcSCody P Schafer * using event parameters. 89816fa7e82SJiri Olsa */ 89999e7138eSJiri Olsa if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 90099e7138eSJiri Olsa if (term->no_value && 90199e7138eSJiri Olsa bitmap_weight(format->bits, PERF_PMU_FORMAT_BITS) > 1) { 90299e7138eSJiri Olsa if (err) { 90399e7138eSJiri Olsa err->idx = term->err_val; 90499e7138eSJiri Olsa err->str = strdup("no value assigned for term"); 90599e7138eSJiri Olsa } 90699e7138eSJiri Olsa return -EINVAL; 90799e7138eSJiri Olsa } 90899e7138eSJiri Olsa 909688d4dfcSCody P Schafer val = term->val.num; 91099e7138eSJiri Olsa } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 911688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 912bb963e16SNamhyung Kim if (verbose > 0) { 913688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 914688d4dfcSCody P Schafer term->config, term->val.str); 915e64b020bSJiri Olsa } 916e64b020bSJiri Olsa if (err) { 917e64b020bSJiri Olsa err->idx = term->err_val; 918e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 919e64b020bSJiri Olsa } 920688d4dfcSCody P Schafer return -EINVAL; 921688d4dfcSCody P Schafer } 922688d4dfcSCody P Schafer 923688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 924688d4dfcSCody P Schafer return -EINVAL; 925688d4dfcSCody P Schafer } else 926688d4dfcSCody P Schafer return -EINVAL; 927688d4dfcSCody P Schafer 9280efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 9290efe6b67SAdrian Hunter if (val > max_val) { 9300efe6b67SAdrian Hunter if (err) { 9310efe6b67SAdrian Hunter err->idx = term->err_val; 9320efe6b67SAdrian Hunter if (asprintf(&err->str, 9330efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 9340efe6b67SAdrian Hunter (unsigned long long)max_val) < 0) 9350efe6b67SAdrian Hunter err->str = strdup("value too big for format"); 9360efe6b67SAdrian Hunter return -EINVAL; 9370efe6b67SAdrian Hunter } 9380efe6b67SAdrian Hunter /* 9390efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 9400efe6b67SAdrian Hunter * silently truncated. 9410efe6b67SAdrian Hunter */ 9420efe6b67SAdrian Hunter } 9430efe6b67SAdrian Hunter 944688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 945cd82a32eSJiri Olsa return 0; 946cd82a32eSJiri Olsa } 947cd82a32eSJiri Olsa 948cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 949cff7f956SJiri Olsa struct perf_event_attr *attr, 950dc0a6202SAdrian Hunter struct list_head *head_terms, 951e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 952cd82a32eSJiri Olsa { 9536cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 954cd82a32eSJiri Olsa 955688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 956e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 957e64b020bSJiri Olsa zero, err)) 958cd82a32eSJiri Olsa return -EINVAL; 959688d4dfcSCody P Schafer } 960cd82a32eSJiri Olsa 961cd82a32eSJiri Olsa return 0; 962cd82a32eSJiri Olsa } 963cd82a32eSJiri Olsa 964cd82a32eSJiri Olsa /* 965cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 966cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 967cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 968cd82a32eSJiri Olsa */ 969cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 970e64b020bSJiri Olsa struct list_head *head_terms, 971e64b020bSJiri Olsa struct parse_events_error *err) 972cd82a32eSJiri Olsa { 973dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 974dc0a6202SAdrian Hunter 975cd82a32eSJiri Olsa attr->type = pmu->type; 976e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 977e64b020bSJiri Olsa zero, err); 978cd82a32eSJiri Olsa } 979cd82a32eSJiri Olsa 9805c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 9816cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 982a6146d50SZheng Yan { 9835c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 984a6146d50SZheng Yan char *name; 985a6146d50SZheng Yan 986a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 987a6146d50SZheng Yan return NULL; 988a6146d50SZheng Yan 989a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 990a6146d50SZheng Yan if (term->val.num != 1) 991a6146d50SZheng Yan return NULL; 992a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 993a6146d50SZheng Yan return NULL; 994a6146d50SZheng Yan name = term->config; 995a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 996a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 997a6146d50SZheng Yan return NULL; 998a6146d50SZheng Yan name = term->val.str; 999a6146d50SZheng Yan } else { 1000a6146d50SZheng Yan return NULL; 1001a6146d50SZheng Yan } 1002a6146d50SZheng Yan 1003a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 1004a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 1005a6146d50SZheng Yan return alias; 1006a6146d50SZheng Yan } 1007a6146d50SZheng Yan return NULL; 1008a6146d50SZheng Yan } 1009a6146d50SZheng Yan 1010410136f5SStephane Eranian 10111d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 10121d9e446bSJiri Olsa struct perf_pmu_info *info) 1013410136f5SStephane Eranian { 1014410136f5SStephane Eranian /* 1015410136f5SStephane Eranian * Only one term in event definition can 10161d9e446bSJiri Olsa * define unit, scale and snapshot, fail 10171d9e446bSJiri Olsa * if there's more than one. 1018410136f5SStephane Eranian */ 1019b30a7d1fSArnaldo Carvalho de Melo if ((info->unit && alias->unit[0]) || 10201d9e446bSJiri Olsa (info->scale && alias->scale) || 10211d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 1022410136f5SStephane Eranian return -EINVAL; 1023410136f5SStephane Eranian 1024b30a7d1fSArnaldo Carvalho de Melo if (alias->unit[0]) 10251d9e446bSJiri Olsa info->unit = alias->unit; 1026410136f5SStephane Eranian 1027410136f5SStephane Eranian if (alias->scale) 10281d9e446bSJiri Olsa info->scale = alias->scale; 10291d9e446bSJiri Olsa 10301d9e446bSJiri Olsa if (alias->snapshot) 10311d9e446bSJiri Olsa info->snapshot = alias->snapshot; 1032410136f5SStephane Eranian 1033410136f5SStephane Eranian return 0; 1034410136f5SStephane Eranian } 1035410136f5SStephane Eranian 1036a6146d50SZheng Yan /* 1037a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 1038a6146d50SZheng Yan * defined for the alias 1039a6146d50SZheng Yan */ 1040410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 104146441bdcSMatt Fleming struct perf_pmu_info *info) 1042a6146d50SZheng Yan { 10436cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 10445c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 1045a6146d50SZheng Yan int ret; 1046a6146d50SZheng Yan 1047044330c1SMatt Fleming info->per_pkg = false; 1048044330c1SMatt Fleming 10498a398897SStephane Eranian /* 10508a398897SStephane Eranian * Mark unit and scale as not set 10518a398897SStephane Eranian * (different from default values, see below) 10528a398897SStephane Eranian */ 105346441bdcSMatt Fleming info->unit = NULL; 105446441bdcSMatt Fleming info->scale = 0.0; 10551d9e446bSJiri Olsa info->snapshot = false; 105637932c18SAndi Kleen info->metric_expr = NULL; 105796284814SAndi Kleen info->metric_name = NULL; 1058410136f5SStephane Eranian 1059a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 1060a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 1061a6146d50SZheng Yan if (!alias) 1062a6146d50SZheng Yan continue; 1063a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 1064a6146d50SZheng Yan if (ret) 1065a6146d50SZheng Yan return ret; 1066410136f5SStephane Eranian 10671d9e446bSJiri Olsa ret = check_info_data(alias, info); 1068410136f5SStephane Eranian if (ret) 1069410136f5SStephane Eranian return ret; 1070410136f5SStephane Eranian 1071044330c1SMatt Fleming if (alias->per_pkg) 1072044330c1SMatt Fleming info->per_pkg = true; 107337932c18SAndi Kleen info->metric_expr = alias->metric_expr; 107496284814SAndi Kleen info->metric_name = alias->metric_name; 1075044330c1SMatt Fleming 1076a6146d50SZheng Yan list_del(&term->list); 1077a6146d50SZheng Yan free(term); 1078a6146d50SZheng Yan } 10798a398897SStephane Eranian 10808a398897SStephane Eranian /* 10818a398897SStephane Eranian * if no unit or scale foundin aliases, then 10828a398897SStephane Eranian * set defaults as for evsel 10838a398897SStephane Eranian * unit cannot left to NULL 10848a398897SStephane Eranian */ 108546441bdcSMatt Fleming if (info->unit == NULL) 108646441bdcSMatt Fleming info->unit = ""; 10878a398897SStephane Eranian 108846441bdcSMatt Fleming if (info->scale == 0.0) 108946441bdcSMatt Fleming info->scale = 1.0; 10908a398897SStephane Eranian 1091a6146d50SZheng Yan return 0; 1092a6146d50SZheng Yan } 1093a6146d50SZheng Yan 1094cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 1095cd82a32eSJiri Olsa int config, unsigned long *bits) 1096cd82a32eSJiri Olsa { 10975c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 1098cd82a32eSJiri Olsa 1099cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 1100cd82a32eSJiri Olsa if (!format) 1101cd82a32eSJiri Olsa return -ENOMEM; 1102cd82a32eSJiri Olsa 1103cd82a32eSJiri Olsa format->name = strdup(name); 1104cd82a32eSJiri Olsa format->value = config; 1105cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 1106cd82a32eSJiri Olsa 1107cd82a32eSJiri Olsa list_add_tail(&format->list, list); 1108cd82a32eSJiri Olsa return 0; 1109cd82a32eSJiri Olsa } 1110cd82a32eSJiri Olsa 1111cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 1112cd82a32eSJiri Olsa { 1113cd82a32eSJiri Olsa long b; 1114cd82a32eSJiri Olsa 1115cd82a32eSJiri Olsa if (!to) 1116cd82a32eSJiri Olsa to = from; 1117cd82a32eSJiri Olsa 111815268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 1119cd82a32eSJiri Olsa for (b = from; b <= to; b++) 1120cd82a32eSJiri Olsa set_bit(b, bits); 1121cd82a32eSJiri Olsa } 1122dc098b35SAndi Kleen 1123aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 1124aaea3617SCody P Schafer { 1125aaea3617SCody P Schafer if (b > a) 1126aaea3617SCody P Schafer return 0; 1127aaea3617SCody P Schafer return a - b; 1128aaea3617SCody P Schafer } 1129aaea3617SCody P Schafer 1130dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 1131dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1132dc098b35SAndi Kleen { 1133aaea3617SCody P Schafer struct parse_events_term *term; 1134aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 1135aaea3617SCody P Schafer 1136aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 1137aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 1138aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 1139aaea3617SCody P Schafer ",%s=%s", term->config, 1140aaea3617SCody P Schafer term->val.str); 1141aaea3617SCody P Schafer } 1142aaea3617SCody P Schafer 1143aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1144aaea3617SCody P Schafer buf[used] = '/'; 1145aaea3617SCody P Schafer used++; 1146aaea3617SCody P Schafer } 1147aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 1148aaea3617SCody P Schafer buf[used] = '\0'; 1149aaea3617SCody P Schafer used++; 1150aaea3617SCody P Schafer } else 1151aaea3617SCody P Schafer buf[len - 1] = '\0'; 1152aaea3617SCody P Schafer 1153dc098b35SAndi Kleen return buf; 1154dc098b35SAndi Kleen } 1155dc098b35SAndi Kleen 1156dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 1157dc098b35SAndi Kleen struct perf_pmu_alias *alias) 1158dc098b35SAndi Kleen { 1159dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 1160dc098b35SAndi Kleen return buf; 1161dc098b35SAndi Kleen } 1162dc098b35SAndi Kleen 1163dd5f1036SAndi Kleen struct sevent { 116408e60ed1SAndi Kleen char *name; 116508e60ed1SAndi Kleen char *desc; 1166dd5f1036SAndi Kleen char *topic; 1167f2361024SAndi Kleen char *str; 1168f2361024SAndi Kleen char *pmu; 11697f372a63SAndi Kleen char *metric_expr; 117096284814SAndi Kleen char *metric_name; 117108e60ed1SAndi Kleen }; 117208e60ed1SAndi Kleen 1173dd5f1036SAndi Kleen static int cmp_sevent(const void *a, const void *b) 1174dc098b35SAndi Kleen { 1175dd5f1036SAndi Kleen const struct sevent *as = a; 1176dd5f1036SAndi Kleen const struct sevent *bs = b; 117708e60ed1SAndi Kleen 117808e60ed1SAndi Kleen /* Put extra events last */ 117908e60ed1SAndi Kleen if (!!as->desc != !!bs->desc) 118008e60ed1SAndi Kleen return !!as->desc - !!bs->desc; 1181dd5f1036SAndi Kleen if (as->topic && bs->topic) { 1182dd5f1036SAndi Kleen int n = strcmp(as->topic, bs->topic); 1183dd5f1036SAndi Kleen 1184dd5f1036SAndi Kleen if (n) 1185dd5f1036SAndi Kleen return n; 1186dd5f1036SAndi Kleen } 118708e60ed1SAndi Kleen return strcmp(as->name, bs->name); 118808e60ed1SAndi Kleen } 118908e60ed1SAndi Kleen 119008e60ed1SAndi Kleen static void wordwrap(char *s, int start, int max, int corr) 119108e60ed1SAndi Kleen { 119208e60ed1SAndi Kleen int column = start; 119308e60ed1SAndi Kleen int n; 119408e60ed1SAndi Kleen 119508e60ed1SAndi Kleen while (*s) { 119608e60ed1SAndi Kleen int wlen = strcspn(s, " \t"); 119708e60ed1SAndi Kleen 119808e60ed1SAndi Kleen if (column + wlen >= max && column > start) { 119908e60ed1SAndi Kleen printf("\n%*s", start, ""); 120008e60ed1SAndi Kleen column = start + corr; 120108e60ed1SAndi Kleen } 120208e60ed1SAndi Kleen n = printf("%s%.*s", column > start ? " " : "", wlen, s); 120308e60ed1SAndi Kleen if (n <= 0) 120408e60ed1SAndi Kleen break; 120508e60ed1SAndi Kleen s += wlen; 120608e60ed1SAndi Kleen column += n; 1207aa4beb10STaeung Song s = ltrim(s); 120808e60ed1SAndi Kleen } 1209dc098b35SAndi Kleen } 1210dc098b35SAndi Kleen 1211c8d6828aSSukadev Bhattiprolu void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1212bf874fcfSAndi Kleen bool long_desc, bool details_flag) 1213dc098b35SAndi Kleen { 1214dc098b35SAndi Kleen struct perf_pmu *pmu; 1215dc098b35SAndi Kleen struct perf_pmu_alias *alias; 1216dc098b35SAndi Kleen char buf[1024]; 1217dc098b35SAndi Kleen int printed = 0; 1218dc098b35SAndi Kleen int len, j; 1219dd5f1036SAndi Kleen struct sevent *aliases; 122008e60ed1SAndi Kleen int numdesc = 0; 122161eb2eb4SAndi Kleen int columns = pager_get_columns(); 1222dd5f1036SAndi Kleen char *topic = NULL; 1223dc098b35SAndi Kleen 1224dc098b35SAndi Kleen pmu = NULL; 1225dc098b35SAndi Kleen len = 0; 122642634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1227dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1228dc098b35SAndi Kleen len++; 122942634bc7SAdrian Hunter if (pmu->selectable) 123042634bc7SAdrian Hunter len++; 123142634bc7SAdrian Hunter } 1232dd5f1036SAndi Kleen aliases = zalloc(sizeof(struct sevent) * len); 1233dc098b35SAndi Kleen if (!aliases) 12347e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1235dc098b35SAndi Kleen pmu = NULL; 1236dc098b35SAndi Kleen j = 0; 123742634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1238dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 123908e60ed1SAndi Kleen char *name = alias->desc ? alias->name : 124008e60ed1SAndi Kleen format_alias(buf, sizeof(buf), pmu, alias); 1241dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1242dc098b35SAndi Kleen 1243dc098b35SAndi Kleen if (event_glob != NULL && 124438d14f0cSAndi Kleen !(strglobmatch_nocase(name, event_glob) || 124538d14f0cSAndi Kleen (!is_cpu && strglobmatch_nocase(alias->name, 124667bdc35fSAndi Kleen event_glob)) || 124767bdc35fSAndi Kleen (alias->topic && 124867bdc35fSAndi Kleen strglobmatch_nocase(alias->topic, event_glob)))) 1249dc098b35SAndi Kleen continue; 12507e4772dcSArnaldo Carvalho de Melo 125108e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 12527e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 12537e4772dcSArnaldo Carvalho de Melo 125408e60ed1SAndi Kleen aliases[j].name = name; 125508e60ed1SAndi Kleen if (is_cpu && !name_only && !alias->desc) 125608e60ed1SAndi Kleen aliases[j].name = format_alias_or(buf, 125708e60ed1SAndi Kleen sizeof(buf), 125808e60ed1SAndi Kleen pmu, alias); 125908e60ed1SAndi Kleen aliases[j].name = strdup(aliases[j].name); 126008e60ed1SAndi Kleen if (!aliases[j].name) 12617e4772dcSArnaldo Carvalho de Melo goto out_enomem; 126208e60ed1SAndi Kleen 1263c8d6828aSSukadev Bhattiprolu aliases[j].desc = long_desc ? alias->long_desc : 1264c8d6828aSSukadev Bhattiprolu alias->desc; 1265dd5f1036SAndi Kleen aliases[j].topic = alias->topic; 1266f2361024SAndi Kleen aliases[j].str = alias->str; 1267f2361024SAndi Kleen aliases[j].pmu = pmu->name; 12687f372a63SAndi Kleen aliases[j].metric_expr = alias->metric_expr; 126996284814SAndi Kleen aliases[j].metric_name = alias->metric_name; 1270dc098b35SAndi Kleen j++; 1271dc098b35SAndi Kleen } 1272fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1273fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 12747e4772dcSArnaldo Carvalho de Melo char *s; 12757e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 12767e4772dcSArnaldo Carvalho de Melo goto out_enomem; 127708e60ed1SAndi Kleen aliases[j].name = s; 127842634bc7SAdrian Hunter j++; 127942634bc7SAdrian Hunter } 128042634bc7SAdrian Hunter } 1281dc098b35SAndi Kleen len = j; 1282dd5f1036SAndi Kleen qsort(aliases, len, sizeof(struct sevent), cmp_sevent); 1283dc098b35SAndi Kleen for (j = 0; j < len; j++) { 128415b22ed3SAndi Kleen /* Skip duplicates */ 128515b22ed3SAndi Kleen if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) 128615b22ed3SAndi Kleen continue; 1287dc098b35SAndi Kleen if (name_only) { 128808e60ed1SAndi Kleen printf("%s ", aliases[j].name); 1289dc098b35SAndi Kleen continue; 1290dc098b35SAndi Kleen } 12911c5f01feSAndi Kleen if (aliases[j].desc && !quiet_flag) { 129208e60ed1SAndi Kleen if (numdesc++ == 0) 129308e60ed1SAndi Kleen printf("\n"); 1294dd5f1036SAndi Kleen if (aliases[j].topic && (!topic || 1295dd5f1036SAndi Kleen strcmp(topic, aliases[j].topic))) { 1296dd5f1036SAndi Kleen printf("%s%s:\n", topic ? "\n" : "", 1297dd5f1036SAndi Kleen aliases[j].topic); 1298dd5f1036SAndi Kleen topic = aliases[j].topic; 1299dd5f1036SAndi Kleen } 130008e60ed1SAndi Kleen printf(" %-50s\n", aliases[j].name); 130108e60ed1SAndi Kleen printf("%*s", 8, "["); 130208e60ed1SAndi Kleen wordwrap(aliases[j].desc, 8, columns, 0); 130308e60ed1SAndi Kleen printf("]\n"); 1304bf874fcfSAndi Kleen if (details_flag) { 13057f372a63SAndi Kleen printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str); 130696284814SAndi Kleen if (aliases[j].metric_name) 130796284814SAndi Kleen printf(" MetricName: %s", aliases[j].metric_name); 13087f372a63SAndi Kleen if (aliases[j].metric_expr) 13097f372a63SAndi Kleen printf(" MetricExpr: %s", aliases[j].metric_expr); 13107f372a63SAndi Kleen putchar('\n'); 13117f372a63SAndi Kleen } 131208e60ed1SAndi Kleen } else 131308e60ed1SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1314dc098b35SAndi Kleen printed++; 1315dc098b35SAndi Kleen } 1316dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1317dc098b35SAndi Kleen printf("\n"); 13187e4772dcSArnaldo Carvalho de Melo out_free: 13197e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 132008e60ed1SAndi Kleen zfree(&aliases[j].name); 13217e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 13227e4772dcSArnaldo Carvalho de Melo return; 13237e4772dcSArnaldo Carvalho de Melo 13247e4772dcSArnaldo Carvalho de Melo out_enomem: 13257e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 13267e4772dcSArnaldo Carvalho de Melo if (aliases) 13277e4772dcSArnaldo Carvalho de Melo goto out_free; 1328dc098b35SAndi Kleen } 13294cabc3d1SAndi Kleen 13304cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 13314cabc3d1SAndi Kleen { 13324cabc3d1SAndi Kleen struct perf_pmu *pmu; 13334cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 13344cabc3d1SAndi Kleen 13354cabc3d1SAndi Kleen pmu = NULL; 13364cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 13374cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 13384cabc3d1SAndi Kleen continue; 13394cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 13404cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 13414cabc3d1SAndi Kleen return true; 13424cabc3d1SAndi Kleen } 13434cabc3d1SAndi Kleen return false; 13444cabc3d1SAndi Kleen } 13457d4bdab5SAdrian Hunter 13467d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 13477d4bdab5SAdrian Hunter { 13487d4bdab5SAdrian Hunter struct stat st; 13497d4bdab5SAdrian Hunter char path[PATH_MAX]; 13507d4bdab5SAdrian Hunter const char *sysfs; 13517d4bdab5SAdrian Hunter 13527d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 13537d4bdab5SAdrian Hunter if (!sysfs) 13547d4bdab5SAdrian Hunter return NULL; 13557d4bdab5SAdrian Hunter 13567d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 13577d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 13587d4bdab5SAdrian Hunter 13597d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 13607d4bdab5SAdrian Hunter return NULL; 13617d4bdab5SAdrian Hunter 13627d4bdab5SAdrian Hunter return fopen(path, "r"); 13637d4bdab5SAdrian Hunter } 13647d4bdab5SAdrian Hunter 13657d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 13667d4bdab5SAdrian Hunter ...) 13677d4bdab5SAdrian Hunter { 13687d4bdab5SAdrian Hunter va_list args; 13697d4bdab5SAdrian Hunter FILE *file; 13707d4bdab5SAdrian Hunter int ret = EOF; 13717d4bdab5SAdrian Hunter 13727d4bdab5SAdrian Hunter va_start(args, fmt); 13737d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 13747d4bdab5SAdrian Hunter if (file) { 13757d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 13767d4bdab5SAdrian Hunter fclose(file); 13777d4bdab5SAdrian Hunter } 13787d4bdab5SAdrian Hunter va_end(args); 13797d4bdab5SAdrian Hunter return ret; 13807d4bdab5SAdrian Hunter } 1381