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" 15cd82a32eSJiri Olsa 16ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 17ab1bf653SArnaldo Carvalho de Melo char *name; 18ab1bf653SArnaldo Carvalho de Melo int value; 19ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 20ab1bf653SArnaldo Carvalho de Melo struct list_head list; 21ab1bf653SArnaldo Carvalho de Melo }; 22ab1bf653SArnaldo Carvalho de Melo 2350a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 2450a9667cSRobert Richter 25cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 26cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 27cd82a32eSJiri Olsa 28cd82a32eSJiri Olsa static LIST_HEAD(pmus); 29cd82a32eSJiri Olsa 30cd82a32eSJiri Olsa /* 31cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 32cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 33cd82a32eSJiri Olsa */ 34cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 35cd82a32eSJiri Olsa { 36cd82a32eSJiri Olsa struct dirent *evt_ent; 37cd82a32eSJiri Olsa DIR *format_dir; 38cd82a32eSJiri Olsa int ret = 0; 39cd82a32eSJiri Olsa 40cd82a32eSJiri Olsa format_dir = opendir(dir); 41cd82a32eSJiri Olsa if (!format_dir) 42cd82a32eSJiri Olsa return -EINVAL; 43cd82a32eSJiri Olsa 44cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 45cd82a32eSJiri Olsa char path[PATH_MAX]; 46cd82a32eSJiri Olsa char *name = evt_ent->d_name; 47cd82a32eSJiri Olsa FILE *file; 48cd82a32eSJiri Olsa 49cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 50cd82a32eSJiri Olsa continue; 51cd82a32eSJiri Olsa 52cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 53cd82a32eSJiri Olsa 54cd82a32eSJiri Olsa ret = -EINVAL; 55cd82a32eSJiri Olsa file = fopen(path, "r"); 56cd82a32eSJiri Olsa if (!file) 57cd82a32eSJiri Olsa break; 58cd82a32eSJiri Olsa 59cd82a32eSJiri Olsa perf_pmu_in = file; 60cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 61cd82a32eSJiri Olsa fclose(file); 62cd82a32eSJiri Olsa } 63cd82a32eSJiri Olsa 64cd82a32eSJiri Olsa closedir(format_dir); 65cd82a32eSJiri Olsa return ret; 66cd82a32eSJiri Olsa } 67cd82a32eSJiri Olsa 68cd82a32eSJiri Olsa /* 69cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 70cd82a32eSJiri Olsa * located at: 71cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 72cd82a32eSJiri Olsa */ 73b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 74cd82a32eSJiri Olsa { 75cd82a32eSJiri Olsa struct stat st; 76cd82a32eSJiri Olsa char path[PATH_MAX]; 77cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 78cd82a32eSJiri Olsa 79cd82a32eSJiri Olsa if (!sysfs) 80cd82a32eSJiri Olsa return -1; 81cd82a32eSJiri Olsa 82cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 8350a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 84cd82a32eSJiri Olsa 85cd82a32eSJiri Olsa if (stat(path, &st) < 0) 869bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 87cd82a32eSJiri Olsa 88cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 89cd82a32eSJiri Olsa return -1; 90cd82a32eSJiri Olsa 91cd82a32eSJiri Olsa return 0; 92cd82a32eSJiri Olsa } 93cd82a32eSJiri Olsa 94410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 95410136f5SStephane Eranian { 96410136f5SStephane Eranian struct stat st; 97410136f5SStephane Eranian ssize_t sret; 98410136f5SStephane Eranian char scale[128]; 99410136f5SStephane Eranian int fd, ret = -1; 100410136f5SStephane Eranian char path[PATH_MAX]; 101ea8f75f9SJiri Olsa char *lc; 102410136f5SStephane Eranian 103410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 104410136f5SStephane Eranian 105410136f5SStephane Eranian fd = open(path, O_RDONLY); 106410136f5SStephane Eranian if (fd == -1) 107410136f5SStephane Eranian return -1; 108410136f5SStephane Eranian 109410136f5SStephane Eranian if (fstat(fd, &st) < 0) 110410136f5SStephane Eranian goto error; 111410136f5SStephane Eranian 112410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 113410136f5SStephane Eranian if (sret < 0) 114410136f5SStephane Eranian goto error; 115410136f5SStephane Eranian 1169ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1179ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1189ecae065SMadhavan Srinivasan else 119410136f5SStephane Eranian scale[sret] = '\0'; 1209ecae065SMadhavan Srinivasan 121410136f5SStephane Eranian /* 122410136f5SStephane Eranian * save current locale 123410136f5SStephane Eranian */ 124410136f5SStephane Eranian lc = setlocale(LC_NUMERIC, NULL); 125410136f5SStephane Eranian 126410136f5SStephane Eranian /* 127f9a5978aSJiri Olsa * The lc string may be allocated in static storage, 128f9a5978aSJiri Olsa * so get a dynamic copy to make it survive setlocale 129f9a5978aSJiri Olsa * call below. 130f9a5978aSJiri Olsa */ 131f9a5978aSJiri Olsa lc = strdup(lc); 132f9a5978aSJiri Olsa if (!lc) { 133f9a5978aSJiri Olsa ret = -ENOMEM; 134f9a5978aSJiri Olsa goto error; 135f9a5978aSJiri Olsa } 136f9a5978aSJiri Olsa 137f9a5978aSJiri Olsa /* 138410136f5SStephane Eranian * force to C locale to ensure kernel 139410136f5SStephane Eranian * scale string is converted correctly. 140410136f5SStephane Eranian * kernel uses default C locale. 141410136f5SStephane Eranian */ 142410136f5SStephane Eranian setlocale(LC_NUMERIC, "C"); 143410136f5SStephane Eranian 144410136f5SStephane Eranian alias->scale = strtod(scale, NULL); 145410136f5SStephane Eranian 146410136f5SStephane Eranian /* restore locale */ 147410136f5SStephane Eranian setlocale(LC_NUMERIC, lc); 148410136f5SStephane Eranian 149ea8f75f9SJiri Olsa free(lc); 150f9a5978aSJiri Olsa 151410136f5SStephane Eranian ret = 0; 152410136f5SStephane Eranian error: 153410136f5SStephane Eranian close(fd); 154410136f5SStephane Eranian return ret; 155410136f5SStephane Eranian } 156410136f5SStephane Eranian 157410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 158410136f5SStephane Eranian { 159410136f5SStephane Eranian char path[PATH_MAX]; 160410136f5SStephane Eranian ssize_t sret; 161410136f5SStephane Eranian int fd; 162410136f5SStephane Eranian 163410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 164410136f5SStephane Eranian 165410136f5SStephane Eranian fd = open(path, O_RDONLY); 166410136f5SStephane Eranian if (fd == -1) 167410136f5SStephane Eranian return -1; 168410136f5SStephane Eranian 169410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 170410136f5SStephane Eranian if (sret < 0) 171410136f5SStephane Eranian goto error; 172410136f5SStephane Eranian 173410136f5SStephane Eranian close(fd); 174410136f5SStephane Eranian 1759ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1769ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1779ecae065SMadhavan Srinivasan else 178410136f5SStephane Eranian alias->unit[sret] = '\0'; 179410136f5SStephane Eranian 180410136f5SStephane Eranian return 0; 181410136f5SStephane Eranian error: 182410136f5SStephane Eranian close(fd); 183410136f5SStephane Eranian alias->unit[0] = '\0'; 184410136f5SStephane Eranian return -1; 185410136f5SStephane Eranian } 186410136f5SStephane Eranian 187044330c1SMatt Fleming static int 188044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 189044330c1SMatt Fleming { 190044330c1SMatt Fleming char path[PATH_MAX]; 191044330c1SMatt Fleming int fd; 192044330c1SMatt Fleming 193044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 194044330c1SMatt Fleming 195044330c1SMatt Fleming fd = open(path, O_RDONLY); 196044330c1SMatt Fleming if (fd == -1) 197044330c1SMatt Fleming return -1; 198044330c1SMatt Fleming 199044330c1SMatt Fleming close(fd); 200044330c1SMatt Fleming 201044330c1SMatt Fleming alias->per_pkg = true; 202044330c1SMatt Fleming return 0; 203044330c1SMatt Fleming } 204044330c1SMatt Fleming 2051d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 2061d9e446bSJiri Olsa char *dir, char *name) 2071d9e446bSJiri Olsa { 2081d9e446bSJiri Olsa char path[PATH_MAX]; 2091d9e446bSJiri Olsa int fd; 2101d9e446bSJiri Olsa 2111d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 2121d9e446bSJiri Olsa 2131d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2141d9e446bSJiri Olsa if (fd == -1) 2151d9e446bSJiri Olsa return -1; 2161d9e446bSJiri Olsa 2171d9e446bSJiri Olsa alias->snapshot = true; 2181d9e446bSJiri Olsa close(fd); 2191d9e446bSJiri Olsa return 0; 2201d9e446bSJiri Olsa } 2211d9e446bSJiri Olsa 22270c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 22370c646e0SSukadev Bhattiprolu char *desc __maybe_unused, char *val) 224a6146d50SZheng Yan { 2255c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 226a6146d50SZheng Yan int ret; 227a6146d50SZheng Yan 228a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 229a6146d50SZheng Yan if (!alias) 230a6146d50SZheng Yan return -ENOMEM; 231a6146d50SZheng Yan 232a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 233410136f5SStephane Eranian alias->scale = 1.0; 234410136f5SStephane Eranian alias->unit[0] = '\0'; 235044330c1SMatt Fleming alias->per_pkg = false; 23684530920SStephane Eranian alias->snapshot = false; 237410136f5SStephane Eranian 23870c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 239a6146d50SZheng Yan if (ret) { 24070c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 241a6146d50SZheng Yan free(alias); 242a6146d50SZheng Yan return ret; 243a6146d50SZheng Yan } 244a6146d50SZheng Yan 245a6146d50SZheng Yan alias->name = strdup(name); 24670c646e0SSukadev Bhattiprolu if (dir) { 247410136f5SStephane Eranian /* 248410136f5SStephane Eranian * load unit name and scale if available 249410136f5SStephane Eranian */ 250410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 251410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 252044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2531d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 25470c646e0SSukadev Bhattiprolu } 255410136f5SStephane Eranian 256a6146d50SZheng Yan list_add_tail(&alias->list, list); 257410136f5SStephane Eranian 258a6146d50SZheng Yan return 0; 259a6146d50SZheng Yan } 260a6146d50SZheng Yan 26170c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 26270c646e0SSukadev Bhattiprolu { 26370c646e0SSukadev Bhattiprolu char buf[256]; 26470c646e0SSukadev Bhattiprolu int ret; 26570c646e0SSukadev Bhattiprolu 26670c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 26770c646e0SSukadev Bhattiprolu if (ret == 0) 26870c646e0SSukadev Bhattiprolu return -EINVAL; 26970c646e0SSukadev Bhattiprolu 27070c646e0SSukadev Bhattiprolu buf[ret] = 0; 27170c646e0SSukadev Bhattiprolu 27270c646e0SSukadev Bhattiprolu return __perf_pmu__new_alias(list, dir, name, NULL, buf); 27370c646e0SSukadev Bhattiprolu } 27470c646e0SSukadev Bhattiprolu 27546441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 27646441bdcSMatt Fleming { 27746441bdcSMatt Fleming size_t len; 27846441bdcSMatt Fleming 27946441bdcSMatt Fleming len = strlen(name); 28046441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 28146441bdcSMatt Fleming return true; 28246441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 28346441bdcSMatt Fleming return true; 284044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 285044330c1SMatt Fleming return true; 2861d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 2871d9e446bSJiri Olsa return true; 28846441bdcSMatt Fleming 28946441bdcSMatt Fleming return false; 29046441bdcSMatt Fleming } 29146441bdcSMatt Fleming 292a6146d50SZheng Yan /* 293a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 294a6146d50SZheng Yan * specified in 'dir' parameter. 295a6146d50SZheng Yan */ 296a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 297a6146d50SZheng Yan { 298a6146d50SZheng Yan struct dirent *evt_ent; 299a6146d50SZheng Yan DIR *event_dir; 300a6146d50SZheng Yan 301a6146d50SZheng Yan event_dir = opendir(dir); 302a6146d50SZheng Yan if (!event_dir) 303a6146d50SZheng Yan return -EINVAL; 304a6146d50SZheng Yan 305940db6dcSAndi Kleen while ((evt_ent = readdir(event_dir))) { 306a6146d50SZheng Yan char path[PATH_MAX]; 307a6146d50SZheng Yan char *name = evt_ent->d_name; 308a6146d50SZheng Yan FILE *file; 309a6146d50SZheng Yan 310a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 311a6146d50SZheng Yan continue; 312a6146d50SZheng Yan 313410136f5SStephane Eranian /* 31446441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 315410136f5SStephane Eranian */ 31646441bdcSMatt Fleming if (pmu_alias_info_file(name)) 317410136f5SStephane Eranian continue; 318410136f5SStephane Eranian 319a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 320a6146d50SZheng Yan 321a6146d50SZheng Yan file = fopen(path, "r"); 322940db6dcSAndi Kleen if (!file) { 323940db6dcSAndi Kleen pr_debug("Cannot open %s\n", path); 324940db6dcSAndi Kleen continue; 325940db6dcSAndi Kleen } 326410136f5SStephane Eranian 327940db6dcSAndi Kleen if (perf_pmu__new_alias(head, dir, name, file) < 0) 328940db6dcSAndi Kleen pr_debug("Cannot set up %s\n", name); 329a6146d50SZheng Yan fclose(file); 330a6146d50SZheng Yan } 331a6146d50SZheng Yan 332a6146d50SZheng Yan closedir(event_dir); 333940db6dcSAndi Kleen return 0; 334a6146d50SZheng Yan } 335a6146d50SZheng Yan 336a6146d50SZheng Yan /* 337a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 338a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 339a6146d50SZheng Yan */ 340b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 341a6146d50SZheng Yan { 342a6146d50SZheng Yan struct stat st; 343a6146d50SZheng Yan char path[PATH_MAX]; 344cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 345a6146d50SZheng Yan 346a6146d50SZheng Yan if (!sysfs) 347a6146d50SZheng Yan return -1; 348a6146d50SZheng Yan 349a6146d50SZheng Yan snprintf(path, PATH_MAX, 350a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 351a6146d50SZheng Yan 352a6146d50SZheng Yan if (stat(path, &st) < 0) 3533fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 354a6146d50SZheng Yan 355a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 356a6146d50SZheng Yan return -1; 357a6146d50SZheng Yan 358a6146d50SZheng Yan return 0; 359a6146d50SZheng Yan } 360a6146d50SZheng Yan 3615c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 362a6146d50SZheng Yan struct list_head *terms) 363a6146d50SZheng Yan { 3647c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 365a6146d50SZheng Yan LIST_HEAD(list); 366a6146d50SZheng Yan int ret; 367a6146d50SZheng Yan 368a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 3697c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 370a6146d50SZheng Yan if (ret) { 371682dc24cSArnaldo Carvalho de Melo parse_events_terms__purge(&list); 372a6146d50SZheng Yan return ret; 373a6146d50SZheng Yan } 3747c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 375a6146d50SZheng Yan } 376a6146d50SZheng Yan list_splice(&list, terms); 377a6146d50SZheng Yan return 0; 378a6146d50SZheng Yan } 379a6146d50SZheng Yan 380cd82a32eSJiri Olsa /* 381cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 382cd82a32eSJiri Olsa * located at: 383cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 384cd82a32eSJiri Olsa */ 385b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 386cd82a32eSJiri Olsa { 387cd82a32eSJiri Olsa struct stat st; 388cd82a32eSJiri Olsa char path[PATH_MAX]; 389cd82a32eSJiri Olsa FILE *file; 390cd82a32eSJiri Olsa int ret = 0; 391cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 392cd82a32eSJiri Olsa 393cd82a32eSJiri Olsa if (!sysfs) 394cd82a32eSJiri Olsa return -1; 395cd82a32eSJiri Olsa 396cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 39750a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 398cd82a32eSJiri Olsa 399cd82a32eSJiri Olsa if (stat(path, &st) < 0) 400cd82a32eSJiri Olsa return -1; 401cd82a32eSJiri Olsa 402cd82a32eSJiri Olsa file = fopen(path, "r"); 403cd82a32eSJiri Olsa if (!file) 404cd82a32eSJiri Olsa return -EINVAL; 405cd82a32eSJiri Olsa 406cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 407cd82a32eSJiri Olsa ret = -1; 408cd82a32eSJiri Olsa 409cd82a32eSJiri Olsa fclose(file); 410cd82a32eSJiri Olsa return ret; 411cd82a32eSJiri Olsa } 412cd82a32eSJiri Olsa 41350a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 41450a9667cSRobert Richter static void pmu_read_sysfs(void) 41550a9667cSRobert Richter { 41650a9667cSRobert Richter char path[PATH_MAX]; 41750a9667cSRobert Richter DIR *dir; 41850a9667cSRobert Richter struct dirent *dent; 419cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 42050a9667cSRobert Richter 42150a9667cSRobert Richter if (!sysfs) 42250a9667cSRobert Richter return; 42350a9667cSRobert Richter 42450a9667cSRobert Richter snprintf(path, PATH_MAX, 42550a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 42650a9667cSRobert Richter 42750a9667cSRobert Richter dir = opendir(path); 42850a9667cSRobert Richter if (!dir) 42950a9667cSRobert Richter return; 43050a9667cSRobert Richter 43150a9667cSRobert Richter while ((dent = readdir(dir))) { 43250a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 43350a9667cSRobert Richter continue; 43450a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 43550a9667cSRobert Richter perf_pmu__find(dent->d_name); 43650a9667cSRobert Richter } 43750a9667cSRobert Richter 43850a9667cSRobert Richter closedir(dir); 43950a9667cSRobert Richter } 44050a9667cSRobert Richter 441b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 4427ae92e74SYan, Zheng { 4437ae92e74SYan, Zheng struct stat st; 4447ae92e74SYan, Zheng char path[PATH_MAX]; 4457ae92e74SYan, Zheng FILE *file; 4467ae92e74SYan, Zheng struct cpu_map *cpus; 447cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 4487e3fcffeSMark Rutland const char *templates[] = { 4497e3fcffeSMark Rutland "%s/bus/event_source/devices/%s/cpumask", 4507e3fcffeSMark Rutland "%s/bus/event_source/devices/%s/cpus", 4517e3fcffeSMark Rutland NULL 4527e3fcffeSMark Rutland }; 4537e3fcffeSMark Rutland const char **template; 4547ae92e74SYan, Zheng 4557ae92e74SYan, Zheng if (!sysfs) 4567ae92e74SYan, Zheng return NULL; 4577ae92e74SYan, Zheng 4587e3fcffeSMark Rutland for (template = templates; *template; template++) { 4597e3fcffeSMark Rutland snprintf(path, PATH_MAX, *template, sysfs, name); 4607e3fcffeSMark Rutland if (stat(path, &st) == 0) 4617e3fcffeSMark Rutland break; 4627e3fcffeSMark Rutland } 4637ae92e74SYan, Zheng 4647e3fcffeSMark Rutland if (!*template) 4657ae92e74SYan, Zheng return NULL; 4667ae92e74SYan, Zheng 4677ae92e74SYan, Zheng file = fopen(path, "r"); 4687ae92e74SYan, Zheng if (!file) 4697ae92e74SYan, Zheng return NULL; 4707ae92e74SYan, Zheng 4717ae92e74SYan, Zheng cpus = cpu_map__read(file); 4727ae92e74SYan, Zheng fclose(file); 4737ae92e74SYan, Zheng return cpus; 4747ae92e74SYan, Zheng } 4757ae92e74SYan, Zheng 476c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 477dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 478dc0a6202SAdrian Hunter { 479dc0a6202SAdrian Hunter return NULL; 480dc0a6202SAdrian Hunter } 481dc0a6202SAdrian Hunter 482b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 483cd82a32eSJiri Olsa { 484cd82a32eSJiri Olsa struct perf_pmu *pmu; 485cd82a32eSJiri Olsa LIST_HEAD(format); 486a6146d50SZheng Yan LIST_HEAD(aliases); 487cd82a32eSJiri Olsa __u32 type; 488cd82a32eSJiri Olsa 489cd82a32eSJiri Olsa /* 490cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 491cd82a32eSJiri Olsa * type value and format definitions. Load both right 492cd82a32eSJiri Olsa * now. 493cd82a32eSJiri Olsa */ 494cd82a32eSJiri Olsa if (pmu_format(name, &format)) 495cd82a32eSJiri Olsa return NULL; 496cd82a32eSJiri Olsa 4973fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 4983fded963SJiri Olsa return NULL; 4993fded963SJiri Olsa 500cd82a32eSJiri Olsa if (pmu_type(name, &type)) 501cd82a32eSJiri Olsa return NULL; 502cd82a32eSJiri Olsa 503cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 504cd82a32eSJiri Olsa if (!pmu) 505cd82a32eSJiri Olsa return NULL; 506cd82a32eSJiri Olsa 5077ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 5087ae92e74SYan, Zheng 509cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 510a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 511cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 512a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 513cd82a32eSJiri Olsa pmu->name = strdup(name); 514cd82a32eSJiri Olsa pmu->type = type; 5159bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 516dc0a6202SAdrian Hunter 517dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 518dc0a6202SAdrian Hunter 519cd82a32eSJiri Olsa return pmu; 520cd82a32eSJiri Olsa } 521cd82a32eSJiri Olsa 522b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 523cd82a32eSJiri Olsa { 524cd82a32eSJiri Olsa struct perf_pmu *pmu; 525cd82a32eSJiri Olsa 526cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 527cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 528cd82a32eSJiri Olsa return pmu; 529cd82a32eSJiri Olsa 530cd82a32eSJiri Olsa return NULL; 531cd82a32eSJiri Olsa } 532cd82a32eSJiri Olsa 53350a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 53450a9667cSRobert Richter { 53550a9667cSRobert Richter /* 53650a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 53750a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 53850a9667cSRobert Richter */ 53950a9667cSRobert Richter if (!pmu) { 54050a9667cSRobert Richter pmu_read_sysfs(); 54150a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 54250a9667cSRobert Richter } 54350a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 54450a9667cSRobert Richter return pmu; 54550a9667cSRobert Richter return NULL; 54650a9667cSRobert Richter } 54750a9667cSRobert Richter 548b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 549cd82a32eSJiri Olsa { 550cd82a32eSJiri Olsa struct perf_pmu *pmu; 551cd82a32eSJiri Olsa 552cd82a32eSJiri Olsa /* 553cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 554cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 555cd82a32eSJiri Olsa * the pmu format definitions. 556cd82a32eSJiri Olsa */ 557cd82a32eSJiri Olsa pmu = pmu_find(name); 558cd82a32eSJiri Olsa if (pmu) 559cd82a32eSJiri Olsa return pmu; 560cd82a32eSJiri Olsa 561cd82a32eSJiri Olsa return pmu_lookup(name); 562cd82a32eSJiri Olsa } 563cd82a32eSJiri Olsa 5645c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 56509ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 566cd82a32eSJiri Olsa { 5675c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 568cd82a32eSJiri Olsa 569cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 570cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 571cd82a32eSJiri Olsa return format; 572cd82a32eSJiri Olsa 573cd82a32eSJiri Olsa return NULL; 574cd82a32eSJiri Olsa } 575cd82a32eSJiri Olsa 57609ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 57709ff6071SAdrian Hunter { 57809ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 57909ff6071SAdrian Hunter __u64 bits = 0; 58009ff6071SAdrian Hunter int fbit; 58109ff6071SAdrian Hunter 58209ff6071SAdrian Hunter if (!format) 58309ff6071SAdrian Hunter return 0; 58409ff6071SAdrian Hunter 58509ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 58609ff6071SAdrian Hunter bits |= 1ULL << fbit; 58709ff6071SAdrian Hunter 58809ff6071SAdrian Hunter return bits; 58909ff6071SAdrian Hunter } 59009ff6071SAdrian Hunter 591cd82a32eSJiri Olsa /* 592dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 593cd82a32eSJiri Olsa * and unformated value (value parameter). 594cd82a32eSJiri Olsa */ 595dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 596dc0a6202SAdrian Hunter bool zero) 597cd82a32eSJiri Olsa { 598cd82a32eSJiri Olsa unsigned long fbit, vbit; 599cd82a32eSJiri Olsa 600cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 601cd82a32eSJiri Olsa 602cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 603cd82a32eSJiri Olsa continue; 604cd82a32eSJiri Olsa 605dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 606dc0a6202SAdrian Hunter *v |= (1llu << fbit); 607dc0a6202SAdrian Hunter else if (zero) 608dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 609cd82a32eSJiri Olsa } 610cd82a32eSJiri Olsa } 611cd82a32eSJiri Olsa 6120efe6b67SAdrian Hunter static __u64 pmu_format_max_value(const unsigned long *format) 6130efe6b67SAdrian Hunter { 614ac0e2cd5SKan Liang __u64 w = 0; 615ac0e2cd5SKan Liang int fbit; 6160efe6b67SAdrian Hunter 617ac0e2cd5SKan Liang for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) 618ac0e2cd5SKan Liang w |= (1ULL << fbit); 619ac0e2cd5SKan Liang 620ac0e2cd5SKan Liang return w; 6210efe6b67SAdrian Hunter } 6220efe6b67SAdrian Hunter 623cd82a32eSJiri Olsa /* 624688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 625688d4dfcSCody P Schafer * in the remaining terms. 626688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 627688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 628688d4dfcSCody P Schafer * in a config string) later on in the term list. 629688d4dfcSCody P Schafer */ 630688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 631688d4dfcSCody P Schafer struct list_head *head_terms, 632688d4dfcSCody P Schafer __u64 *value) 633688d4dfcSCody P Schafer { 634688d4dfcSCody P Schafer struct parse_events_term *t; 635688d4dfcSCody P Schafer 636688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 637688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 638688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 639688d4dfcSCody P Schafer t->used = true; 640688d4dfcSCody P Schafer *value = t->val.num; 641688d4dfcSCody P Schafer return 0; 642688d4dfcSCody P Schafer } 643688d4dfcSCody P Schafer } 644688d4dfcSCody P Schafer } 645688d4dfcSCody P Schafer 646688d4dfcSCody P Schafer if (verbose) 647688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 648688d4dfcSCody P Schafer 649688d4dfcSCody P Schafer return -1; 650688d4dfcSCody P Schafer } 651688d4dfcSCody P Schafer 652ffeb883eSHe Kuang static char *pmu_formats_string(struct list_head *formats) 653e64b020bSJiri Olsa { 654e64b020bSJiri Olsa struct perf_pmu_format *format; 65511db4e29SMasami Hiramatsu char *str = NULL; 65611db4e29SMasami Hiramatsu struct strbuf buf = STRBUF_INIT; 657e64b020bSJiri Olsa unsigned i = 0; 658e64b020bSJiri Olsa 659ffeb883eSHe Kuang if (!formats) 660e64b020bSJiri Olsa return NULL; 661e64b020bSJiri Olsa 662e64b020bSJiri Olsa /* sysfs exported terms */ 663ffeb883eSHe Kuang list_for_each_entry(format, formats, list) 66411db4e29SMasami Hiramatsu if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) 66511db4e29SMasami Hiramatsu goto error; 666e64b020bSJiri Olsa 667ffeb883eSHe Kuang str = strbuf_detach(&buf, NULL); 66811db4e29SMasami Hiramatsu error: 669ffeb883eSHe Kuang strbuf_release(&buf); 670e64b020bSJiri Olsa 671e64b020bSJiri Olsa return str; 672e64b020bSJiri Olsa } 673e64b020bSJiri Olsa 674688d4dfcSCody P Schafer /* 675cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 67688aca8d9SCody P Schafer * user input data - term parameter. 677cd82a32eSJiri Olsa */ 678cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 679cd82a32eSJiri Olsa struct perf_event_attr *attr, 680dc0a6202SAdrian Hunter struct parse_events_term *term, 681688d4dfcSCody P Schafer struct list_head *head_terms, 682e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 683cd82a32eSJiri Olsa { 6845c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 685cd82a32eSJiri Olsa __u64 *vp; 6860efe6b67SAdrian Hunter __u64 val, max_val; 687cd82a32eSJiri Olsa 688cd82a32eSJiri Olsa /* 689688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 690688d4dfcSCody P Schafer * skip it in normal eval. 691688d4dfcSCody P Schafer */ 692688d4dfcSCody P Schafer if (term->used) 693688d4dfcSCody P Schafer return 0; 694688d4dfcSCody P Schafer 695688d4dfcSCody P Schafer /* 696cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 697cd82a32eSJiri Olsa * to be done for them. 698cd82a32eSJiri Olsa */ 699cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 700cd82a32eSJiri Olsa return 0; 701cd82a32eSJiri Olsa 702cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 703688d4dfcSCody P Schafer if (!format) { 704688d4dfcSCody P Schafer if (verbose) 705688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 706e64b020bSJiri Olsa if (err) { 707ffeb883eSHe Kuang char *pmu_term = pmu_formats_string(formats); 708ffeb883eSHe Kuang 709e64b020bSJiri Olsa err->idx = term->err_term; 710e64b020bSJiri Olsa err->str = strdup("unknown term"); 711ffeb883eSHe Kuang err->help = parse_events_formats_error_string(pmu_term); 712ffeb883eSHe Kuang free(pmu_term); 713e64b020bSJiri Olsa } 714cd82a32eSJiri Olsa return -EINVAL; 715688d4dfcSCody P Schafer } 716cd82a32eSJiri Olsa 717cd82a32eSJiri Olsa switch (format->value) { 718cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 719cd82a32eSJiri Olsa vp = &attr->config; 720cd82a32eSJiri Olsa break; 721cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 722cd82a32eSJiri Olsa vp = &attr->config1; 723cd82a32eSJiri Olsa break; 724cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 725cd82a32eSJiri Olsa vp = &attr->config2; 726cd82a32eSJiri Olsa break; 727cd82a32eSJiri Olsa default: 728cd82a32eSJiri Olsa return -EINVAL; 729cd82a32eSJiri Olsa } 730cd82a32eSJiri Olsa 73116fa7e82SJiri Olsa /* 732688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 733688d4dfcSCody P Schafer * using event parameters. 73416fa7e82SJiri Olsa */ 735688d4dfcSCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 736688d4dfcSCody P Schafer val = term->val.num; 737688d4dfcSCody P Schafer else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 738688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 739e64b020bSJiri Olsa if (verbose) { 740688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 741688d4dfcSCody P Schafer term->config, term->val.str); 742e64b020bSJiri Olsa } 743e64b020bSJiri Olsa if (err) { 744e64b020bSJiri Olsa err->idx = term->err_val; 745e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 746e64b020bSJiri Olsa } 747688d4dfcSCody P Schafer return -EINVAL; 748688d4dfcSCody P Schafer } 749688d4dfcSCody P Schafer 750688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 751688d4dfcSCody P Schafer return -EINVAL; 752688d4dfcSCody P Schafer } else 753688d4dfcSCody P Schafer return -EINVAL; 754688d4dfcSCody P Schafer 7550efe6b67SAdrian Hunter max_val = pmu_format_max_value(format->bits); 7560efe6b67SAdrian Hunter if (val > max_val) { 7570efe6b67SAdrian Hunter if (err) { 7580efe6b67SAdrian Hunter err->idx = term->err_val; 7590efe6b67SAdrian Hunter if (asprintf(&err->str, 7600efe6b67SAdrian Hunter "value too big for format, maximum is %llu", 7610efe6b67SAdrian Hunter (unsigned long long)max_val) < 0) 7620efe6b67SAdrian Hunter err->str = strdup("value too big for format"); 7630efe6b67SAdrian Hunter return -EINVAL; 7640efe6b67SAdrian Hunter } 7650efe6b67SAdrian Hunter /* 7660efe6b67SAdrian Hunter * Assume we don't care if !err, in which case the value will be 7670efe6b67SAdrian Hunter * silently truncated. 7680efe6b67SAdrian Hunter */ 7690efe6b67SAdrian Hunter } 7700efe6b67SAdrian Hunter 771688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 772cd82a32eSJiri Olsa return 0; 773cd82a32eSJiri Olsa } 774cd82a32eSJiri Olsa 775cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 776cff7f956SJiri Olsa struct perf_event_attr *attr, 777dc0a6202SAdrian Hunter struct list_head *head_terms, 778e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 779cd82a32eSJiri Olsa { 7806cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 781cd82a32eSJiri Olsa 782688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 783e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 784e64b020bSJiri Olsa zero, err)) 785cd82a32eSJiri Olsa return -EINVAL; 786688d4dfcSCody P Schafer } 787cd82a32eSJiri Olsa 788cd82a32eSJiri Olsa return 0; 789cd82a32eSJiri Olsa } 790cd82a32eSJiri Olsa 791cd82a32eSJiri Olsa /* 792cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 793cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 794cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 795cd82a32eSJiri Olsa */ 796cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 797e64b020bSJiri Olsa struct list_head *head_terms, 798e64b020bSJiri Olsa struct parse_events_error *err) 799cd82a32eSJiri Olsa { 800dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 801dc0a6202SAdrian Hunter 802cd82a32eSJiri Olsa attr->type = pmu->type; 803e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 804e64b020bSJiri Olsa zero, err); 805cd82a32eSJiri Olsa } 806cd82a32eSJiri Olsa 8075c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 8086cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 809a6146d50SZheng Yan { 8105c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 811a6146d50SZheng Yan char *name; 812a6146d50SZheng Yan 813a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 814a6146d50SZheng Yan return NULL; 815a6146d50SZheng Yan 816a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 817a6146d50SZheng Yan if (term->val.num != 1) 818a6146d50SZheng Yan return NULL; 819a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 820a6146d50SZheng Yan return NULL; 821a6146d50SZheng Yan name = term->config; 822a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 823a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 824a6146d50SZheng Yan return NULL; 825a6146d50SZheng Yan name = term->val.str; 826a6146d50SZheng Yan } else { 827a6146d50SZheng Yan return NULL; 828a6146d50SZheng Yan } 829a6146d50SZheng Yan 830a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 831a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 832a6146d50SZheng Yan return alias; 833a6146d50SZheng Yan } 834a6146d50SZheng Yan return NULL; 835a6146d50SZheng Yan } 836a6146d50SZheng Yan 837410136f5SStephane Eranian 8381d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 8391d9e446bSJiri Olsa struct perf_pmu_info *info) 840410136f5SStephane Eranian { 841410136f5SStephane Eranian /* 842410136f5SStephane Eranian * Only one term in event definition can 8431d9e446bSJiri Olsa * define unit, scale and snapshot, fail 8441d9e446bSJiri Olsa * if there's more than one. 845410136f5SStephane Eranian */ 8461d9e446bSJiri Olsa if ((info->unit && alias->unit) || 8471d9e446bSJiri Olsa (info->scale && alias->scale) || 8481d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 849410136f5SStephane Eranian return -EINVAL; 850410136f5SStephane Eranian 851410136f5SStephane Eranian if (alias->unit) 8521d9e446bSJiri Olsa info->unit = alias->unit; 853410136f5SStephane Eranian 854410136f5SStephane Eranian if (alias->scale) 8551d9e446bSJiri Olsa info->scale = alias->scale; 8561d9e446bSJiri Olsa 8571d9e446bSJiri Olsa if (alias->snapshot) 8581d9e446bSJiri Olsa info->snapshot = alias->snapshot; 859410136f5SStephane Eranian 860410136f5SStephane Eranian return 0; 861410136f5SStephane Eranian } 862410136f5SStephane Eranian 863a6146d50SZheng Yan /* 864a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 865a6146d50SZheng Yan * defined for the alias 866a6146d50SZheng Yan */ 867410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 86846441bdcSMatt Fleming struct perf_pmu_info *info) 869a6146d50SZheng Yan { 8706cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 8715c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 872a6146d50SZheng Yan int ret; 873a6146d50SZheng Yan 874044330c1SMatt Fleming info->per_pkg = false; 875044330c1SMatt Fleming 8768a398897SStephane Eranian /* 8778a398897SStephane Eranian * Mark unit and scale as not set 8788a398897SStephane Eranian * (different from default values, see below) 8798a398897SStephane Eranian */ 88046441bdcSMatt Fleming info->unit = NULL; 88146441bdcSMatt Fleming info->scale = 0.0; 8821d9e446bSJiri Olsa info->snapshot = false; 883410136f5SStephane Eranian 884a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 885a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 886a6146d50SZheng Yan if (!alias) 887a6146d50SZheng Yan continue; 888a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 889a6146d50SZheng Yan if (ret) 890a6146d50SZheng Yan return ret; 891410136f5SStephane Eranian 8921d9e446bSJiri Olsa ret = check_info_data(alias, info); 893410136f5SStephane Eranian if (ret) 894410136f5SStephane Eranian return ret; 895410136f5SStephane Eranian 896044330c1SMatt Fleming if (alias->per_pkg) 897044330c1SMatt Fleming info->per_pkg = true; 898044330c1SMatt Fleming 899a6146d50SZheng Yan list_del(&term->list); 900a6146d50SZheng Yan free(term); 901a6146d50SZheng Yan } 9028a398897SStephane Eranian 9038a398897SStephane Eranian /* 9048a398897SStephane Eranian * if no unit or scale foundin aliases, then 9058a398897SStephane Eranian * set defaults as for evsel 9068a398897SStephane Eranian * unit cannot left to NULL 9078a398897SStephane Eranian */ 90846441bdcSMatt Fleming if (info->unit == NULL) 90946441bdcSMatt Fleming info->unit = ""; 9108a398897SStephane Eranian 91146441bdcSMatt Fleming if (info->scale == 0.0) 91246441bdcSMatt Fleming info->scale = 1.0; 9138a398897SStephane Eranian 914a6146d50SZheng Yan return 0; 915a6146d50SZheng Yan } 916a6146d50SZheng Yan 917cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 918cd82a32eSJiri Olsa int config, unsigned long *bits) 919cd82a32eSJiri Olsa { 9205c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 921cd82a32eSJiri Olsa 922cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 923cd82a32eSJiri Olsa if (!format) 924cd82a32eSJiri Olsa return -ENOMEM; 925cd82a32eSJiri Olsa 926cd82a32eSJiri Olsa format->name = strdup(name); 927cd82a32eSJiri Olsa format->value = config; 928cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 929cd82a32eSJiri Olsa 930cd82a32eSJiri Olsa list_add_tail(&format->list, list); 931cd82a32eSJiri Olsa return 0; 932cd82a32eSJiri Olsa } 933cd82a32eSJiri Olsa 934cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 935cd82a32eSJiri Olsa { 936cd82a32eSJiri Olsa long b; 937cd82a32eSJiri Olsa 938cd82a32eSJiri Olsa if (!to) 939cd82a32eSJiri Olsa to = from; 940cd82a32eSJiri Olsa 94115268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 942cd82a32eSJiri Olsa for (b = from; b <= to; b++) 943cd82a32eSJiri Olsa set_bit(b, bits); 944cd82a32eSJiri Olsa } 945dc098b35SAndi Kleen 946aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 947aaea3617SCody P Schafer { 948aaea3617SCody P Schafer if (b > a) 949aaea3617SCody P Schafer return 0; 950aaea3617SCody P Schafer return a - b; 951aaea3617SCody P Schafer } 952aaea3617SCody P Schafer 953dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 954dc098b35SAndi Kleen struct perf_pmu_alias *alias) 955dc098b35SAndi Kleen { 956aaea3617SCody P Schafer struct parse_events_term *term; 957aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 958aaea3617SCody P Schafer 959aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 960aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 961aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 962aaea3617SCody P Schafer ",%s=%s", term->config, 963aaea3617SCody P Schafer term->val.str); 964aaea3617SCody P Schafer } 965aaea3617SCody P Schafer 966aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 967aaea3617SCody P Schafer buf[used] = '/'; 968aaea3617SCody P Schafer used++; 969aaea3617SCody P Schafer } 970aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 971aaea3617SCody P Schafer buf[used] = '\0'; 972aaea3617SCody P Schafer used++; 973aaea3617SCody P Schafer } else 974aaea3617SCody P Schafer buf[len - 1] = '\0'; 975aaea3617SCody P Schafer 976dc098b35SAndi Kleen return buf; 977dc098b35SAndi Kleen } 978dc098b35SAndi Kleen 979dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 980dc098b35SAndi Kleen struct perf_pmu_alias *alias) 981dc098b35SAndi Kleen { 982dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 983dc098b35SAndi Kleen return buf; 984dc098b35SAndi Kleen } 985dc098b35SAndi Kleen 986dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b) 987dc098b35SAndi Kleen { 988dc098b35SAndi Kleen const char * const *as = a; 989dc098b35SAndi Kleen const char * const *bs = b; 990dc098b35SAndi Kleen return strcmp(*as, *bs); 991dc098b35SAndi Kleen } 992dc098b35SAndi Kleen 993dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only) 994dc098b35SAndi Kleen { 995dc098b35SAndi Kleen struct perf_pmu *pmu; 996dc098b35SAndi Kleen struct perf_pmu_alias *alias; 997dc098b35SAndi Kleen char buf[1024]; 998dc098b35SAndi Kleen int printed = 0; 999dc098b35SAndi Kleen int len, j; 1000dc098b35SAndi Kleen char **aliases; 1001dc098b35SAndi Kleen 1002dc098b35SAndi Kleen pmu = NULL; 1003dc098b35SAndi Kleen len = 0; 100442634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1005dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 1006dc098b35SAndi Kleen len++; 100742634bc7SAdrian Hunter if (pmu->selectable) 100842634bc7SAdrian Hunter len++; 100942634bc7SAdrian Hunter } 10107e4772dcSArnaldo Carvalho de Melo aliases = zalloc(sizeof(char *) * len); 1011dc098b35SAndi Kleen if (!aliases) 10127e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1013dc098b35SAndi Kleen pmu = NULL; 1014dc098b35SAndi Kleen j = 0; 101542634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1016dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 1017dc098b35SAndi Kleen char *name = format_alias(buf, sizeof(buf), pmu, alias); 1018dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 1019dc098b35SAndi Kleen 1020dc098b35SAndi Kleen if (event_glob != NULL && 1021dc098b35SAndi Kleen !(strglobmatch(name, event_glob) || 1022dc098b35SAndi Kleen (!is_cpu && strglobmatch(alias->name, 1023dc098b35SAndi Kleen event_glob)))) 1024dc098b35SAndi Kleen continue; 10257e4772dcSArnaldo Carvalho de Melo 1026dc098b35SAndi Kleen if (is_cpu && !name_only) 10277e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 10287e4772dcSArnaldo Carvalho de Melo 10297e4772dcSArnaldo Carvalho de Melo aliases[j] = strdup(name); 10307e4772dcSArnaldo Carvalho de Melo if (aliases[j] == NULL) 10317e4772dcSArnaldo Carvalho de Melo goto out_enomem; 1032dc098b35SAndi Kleen j++; 1033dc098b35SAndi Kleen } 1034fa52ceabSArnaldo Carvalho de Melo if (pmu->selectable && 1035fa52ceabSArnaldo Carvalho de Melo (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { 10367e4772dcSArnaldo Carvalho de Melo char *s; 10377e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 10387e4772dcSArnaldo Carvalho de Melo goto out_enomem; 10397e4772dcSArnaldo Carvalho de Melo aliases[j] = s; 104042634bc7SAdrian Hunter j++; 104142634bc7SAdrian Hunter } 104242634bc7SAdrian Hunter } 1043dc098b35SAndi Kleen len = j; 1044dc098b35SAndi Kleen qsort(aliases, len, sizeof(char *), cmp_string); 1045dc098b35SAndi Kleen for (j = 0; j < len; j++) { 1046dc098b35SAndi Kleen if (name_only) { 1047dc098b35SAndi Kleen printf("%s ", aliases[j]); 1048dc098b35SAndi Kleen continue; 1049dc098b35SAndi Kleen } 1050dc098b35SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j]); 1051dc098b35SAndi Kleen printed++; 1052dc098b35SAndi Kleen } 1053dfc431cbSArnaldo Carvalho de Melo if (printed && pager_in_use()) 1054dc098b35SAndi Kleen printf("\n"); 10557e4772dcSArnaldo Carvalho de Melo out_free: 10567e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 10577e4772dcSArnaldo Carvalho de Melo zfree(&aliases[j]); 10587e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 10597e4772dcSArnaldo Carvalho de Melo return; 10607e4772dcSArnaldo Carvalho de Melo 10617e4772dcSArnaldo Carvalho de Melo out_enomem: 10627e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 10637e4772dcSArnaldo Carvalho de Melo if (aliases) 10647e4772dcSArnaldo Carvalho de Melo goto out_free; 1065dc098b35SAndi Kleen } 10664cabc3d1SAndi Kleen 10674cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 10684cabc3d1SAndi Kleen { 10694cabc3d1SAndi Kleen struct perf_pmu *pmu; 10704cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 10714cabc3d1SAndi Kleen 10724cabc3d1SAndi Kleen pmu = NULL; 10734cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 10744cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 10754cabc3d1SAndi Kleen continue; 10764cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 10774cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 10784cabc3d1SAndi Kleen return true; 10794cabc3d1SAndi Kleen } 10804cabc3d1SAndi Kleen return false; 10814cabc3d1SAndi Kleen } 10827d4bdab5SAdrian Hunter 10837d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 10847d4bdab5SAdrian Hunter { 10857d4bdab5SAdrian Hunter struct stat st; 10867d4bdab5SAdrian Hunter char path[PATH_MAX]; 10877d4bdab5SAdrian Hunter const char *sysfs; 10887d4bdab5SAdrian Hunter 10897d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 10907d4bdab5SAdrian Hunter if (!sysfs) 10917d4bdab5SAdrian Hunter return NULL; 10927d4bdab5SAdrian Hunter 10937d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 10947d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 10957d4bdab5SAdrian Hunter 10967d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 10977d4bdab5SAdrian Hunter return NULL; 10987d4bdab5SAdrian Hunter 10997d4bdab5SAdrian Hunter return fopen(path, "r"); 11007d4bdab5SAdrian Hunter } 11017d4bdab5SAdrian Hunter 11027d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 11037d4bdab5SAdrian Hunter ...) 11047d4bdab5SAdrian Hunter { 11057d4bdab5SAdrian Hunter va_list args; 11067d4bdab5SAdrian Hunter FILE *file; 11077d4bdab5SAdrian Hunter int ret = EOF; 11087d4bdab5SAdrian Hunter 11097d4bdab5SAdrian Hunter va_start(args, fmt); 11107d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 11117d4bdab5SAdrian Hunter if (file) { 11127d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 11137d4bdab5SAdrian Hunter fclose(file); 11147d4bdab5SAdrian Hunter } 11157d4bdab5SAdrian Hunter va_end(args); 11167d4bdab5SAdrian Hunter return ret; 11177d4bdab5SAdrian Hunter } 1118