1cd82a32eSJiri Olsa #include <linux/list.h> 2cd82a32eSJiri Olsa #include <sys/types.h> 3cd82a32eSJiri Olsa #include <unistd.h> 4cd82a32eSJiri Olsa #include <stdio.h> 5dc0a6202SAdrian Hunter #include <stdbool.h> 67d4bdab5SAdrian Hunter #include <stdarg.h> 7cd82a32eSJiri Olsa #include <dirent.h> 8cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 9410136f5SStephane Eranian #include <locale.h> 10cd82a32eSJiri Olsa #include "util.h" 11cd82a32eSJiri Olsa #include "pmu.h" 12cd82a32eSJiri Olsa #include "parse-events.h" 137ae92e74SYan, Zheng #include "cpumap.h" 14cd82a32eSJiri Olsa 15ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 16ab1bf653SArnaldo Carvalho de Melo char *name; 17ab1bf653SArnaldo Carvalho de Melo int value; 18ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 19ab1bf653SArnaldo Carvalho de Melo struct list_head list; 20ab1bf653SArnaldo Carvalho de Melo }; 21ab1bf653SArnaldo Carvalho de Melo 2250a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 2350a9667cSRobert Richter 24cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 25cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 26cd82a32eSJiri Olsa 27cd82a32eSJiri Olsa static LIST_HEAD(pmus); 28cd82a32eSJiri Olsa 29cd82a32eSJiri Olsa /* 30cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 31cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 32cd82a32eSJiri Olsa */ 33cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 34cd82a32eSJiri Olsa { 35cd82a32eSJiri Olsa struct dirent *evt_ent; 36cd82a32eSJiri Olsa DIR *format_dir; 37cd82a32eSJiri Olsa int ret = 0; 38cd82a32eSJiri Olsa 39cd82a32eSJiri Olsa format_dir = opendir(dir); 40cd82a32eSJiri Olsa if (!format_dir) 41cd82a32eSJiri Olsa return -EINVAL; 42cd82a32eSJiri Olsa 43cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 44cd82a32eSJiri Olsa char path[PATH_MAX]; 45cd82a32eSJiri Olsa char *name = evt_ent->d_name; 46cd82a32eSJiri Olsa FILE *file; 47cd82a32eSJiri Olsa 48cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 49cd82a32eSJiri Olsa continue; 50cd82a32eSJiri Olsa 51cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 52cd82a32eSJiri Olsa 53cd82a32eSJiri Olsa ret = -EINVAL; 54cd82a32eSJiri Olsa file = fopen(path, "r"); 55cd82a32eSJiri Olsa if (!file) 56cd82a32eSJiri Olsa break; 57cd82a32eSJiri Olsa 58cd82a32eSJiri Olsa perf_pmu_in = file; 59cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 60cd82a32eSJiri Olsa fclose(file); 61cd82a32eSJiri Olsa } 62cd82a32eSJiri Olsa 63cd82a32eSJiri Olsa closedir(format_dir); 64cd82a32eSJiri Olsa return ret; 65cd82a32eSJiri Olsa } 66cd82a32eSJiri Olsa 67cd82a32eSJiri Olsa /* 68cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 69cd82a32eSJiri Olsa * located at: 70cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 71cd82a32eSJiri Olsa */ 72b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 73cd82a32eSJiri Olsa { 74cd82a32eSJiri Olsa struct stat st; 75cd82a32eSJiri Olsa char path[PATH_MAX]; 76cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 77cd82a32eSJiri Olsa 78cd82a32eSJiri Olsa if (!sysfs) 79cd82a32eSJiri Olsa return -1; 80cd82a32eSJiri Olsa 81cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 8250a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 83cd82a32eSJiri Olsa 84cd82a32eSJiri Olsa if (stat(path, &st) < 0) 859bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 86cd82a32eSJiri Olsa 87cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 88cd82a32eSJiri Olsa return -1; 89cd82a32eSJiri Olsa 90cd82a32eSJiri Olsa return 0; 91cd82a32eSJiri Olsa } 92cd82a32eSJiri Olsa 93410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 94410136f5SStephane Eranian { 95410136f5SStephane Eranian struct stat st; 96410136f5SStephane Eranian ssize_t sret; 97410136f5SStephane Eranian char scale[128]; 98410136f5SStephane Eranian int fd, ret = -1; 99410136f5SStephane Eranian char path[PATH_MAX]; 1008a398897SStephane Eranian const char *lc; 101410136f5SStephane Eranian 102410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 103410136f5SStephane Eranian 104410136f5SStephane Eranian fd = open(path, O_RDONLY); 105410136f5SStephane Eranian if (fd == -1) 106410136f5SStephane Eranian return -1; 107410136f5SStephane Eranian 108410136f5SStephane Eranian if (fstat(fd, &st) < 0) 109410136f5SStephane Eranian goto error; 110410136f5SStephane Eranian 111410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 112410136f5SStephane Eranian if (sret < 0) 113410136f5SStephane Eranian goto error; 114410136f5SStephane Eranian 115410136f5SStephane Eranian scale[sret] = '\0'; 116410136f5SStephane Eranian /* 117410136f5SStephane Eranian * save current locale 118410136f5SStephane Eranian */ 119410136f5SStephane Eranian lc = setlocale(LC_NUMERIC, NULL); 120410136f5SStephane Eranian 121410136f5SStephane Eranian /* 122410136f5SStephane Eranian * force to C locale to ensure kernel 123410136f5SStephane Eranian * scale string is converted correctly. 124410136f5SStephane Eranian * kernel uses default C locale. 125410136f5SStephane Eranian */ 126410136f5SStephane Eranian setlocale(LC_NUMERIC, "C"); 127410136f5SStephane Eranian 128410136f5SStephane Eranian alias->scale = strtod(scale, NULL); 129410136f5SStephane Eranian 130410136f5SStephane Eranian /* restore locale */ 131410136f5SStephane Eranian setlocale(LC_NUMERIC, lc); 132410136f5SStephane Eranian 133410136f5SStephane Eranian ret = 0; 134410136f5SStephane Eranian error: 135410136f5SStephane Eranian close(fd); 136410136f5SStephane Eranian return ret; 137410136f5SStephane Eranian } 138410136f5SStephane Eranian 139410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 140410136f5SStephane Eranian { 141410136f5SStephane Eranian char path[PATH_MAX]; 142410136f5SStephane Eranian ssize_t sret; 143410136f5SStephane Eranian int fd; 144410136f5SStephane Eranian 145410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 146410136f5SStephane Eranian 147410136f5SStephane Eranian fd = open(path, O_RDONLY); 148410136f5SStephane Eranian if (fd == -1) 149410136f5SStephane Eranian return -1; 150410136f5SStephane Eranian 151410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 152410136f5SStephane Eranian if (sret < 0) 153410136f5SStephane Eranian goto error; 154410136f5SStephane Eranian 155410136f5SStephane Eranian close(fd); 156410136f5SStephane Eranian 157410136f5SStephane Eranian alias->unit[sret] = '\0'; 158410136f5SStephane Eranian 159410136f5SStephane Eranian return 0; 160410136f5SStephane Eranian error: 161410136f5SStephane Eranian close(fd); 162410136f5SStephane Eranian alias->unit[0] = '\0'; 163410136f5SStephane Eranian return -1; 164410136f5SStephane Eranian } 165410136f5SStephane Eranian 166044330c1SMatt Fleming static int 167044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 168044330c1SMatt Fleming { 169044330c1SMatt Fleming char path[PATH_MAX]; 170044330c1SMatt Fleming int fd; 171044330c1SMatt Fleming 172044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 173044330c1SMatt Fleming 174044330c1SMatt Fleming fd = open(path, O_RDONLY); 175044330c1SMatt Fleming if (fd == -1) 176044330c1SMatt Fleming return -1; 177044330c1SMatt Fleming 178044330c1SMatt Fleming close(fd); 179044330c1SMatt Fleming 180044330c1SMatt Fleming alias->per_pkg = true; 181044330c1SMatt Fleming return 0; 182044330c1SMatt Fleming } 183044330c1SMatt Fleming 1841d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 1851d9e446bSJiri Olsa char *dir, char *name) 1861d9e446bSJiri Olsa { 1871d9e446bSJiri Olsa char path[PATH_MAX]; 1881d9e446bSJiri Olsa int fd; 1891d9e446bSJiri Olsa 1901d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 1911d9e446bSJiri Olsa 1921d9e446bSJiri Olsa fd = open(path, O_RDONLY); 1931d9e446bSJiri Olsa if (fd == -1) 1941d9e446bSJiri Olsa return -1; 1951d9e446bSJiri Olsa 1961d9e446bSJiri Olsa alias->snapshot = true; 1971d9e446bSJiri Olsa close(fd); 1981d9e446bSJiri Olsa return 0; 1991d9e446bSJiri Olsa } 2001d9e446bSJiri Olsa 201410136f5SStephane Eranian static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 202a6146d50SZheng Yan { 2035c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 204a6146d50SZheng Yan char buf[256]; 205a6146d50SZheng Yan int ret; 206a6146d50SZheng Yan 207a6146d50SZheng Yan ret = fread(buf, 1, sizeof(buf), file); 208a6146d50SZheng Yan if (ret == 0) 209a6146d50SZheng Yan return -EINVAL; 210a6146d50SZheng Yan buf[ret] = 0; 211a6146d50SZheng Yan 212a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 213a6146d50SZheng Yan if (!alias) 214a6146d50SZheng Yan return -ENOMEM; 215a6146d50SZheng Yan 216a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 217410136f5SStephane Eranian alias->scale = 1.0; 218410136f5SStephane Eranian alias->unit[0] = '\0'; 219044330c1SMatt Fleming alias->per_pkg = false; 220410136f5SStephane Eranian 221a6146d50SZheng Yan ret = parse_events_terms(&alias->terms, buf); 222a6146d50SZheng Yan if (ret) { 223a6146d50SZheng Yan free(alias); 224a6146d50SZheng Yan return ret; 225a6146d50SZheng Yan } 226a6146d50SZheng Yan 227a6146d50SZheng Yan alias->name = strdup(name); 228410136f5SStephane Eranian /* 229410136f5SStephane Eranian * load unit name and scale if available 230410136f5SStephane Eranian */ 231410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 232410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 233044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2341d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 235410136f5SStephane Eranian 236a6146d50SZheng Yan list_add_tail(&alias->list, list); 237410136f5SStephane Eranian 238a6146d50SZheng Yan return 0; 239a6146d50SZheng Yan } 240a6146d50SZheng Yan 24146441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 24246441bdcSMatt Fleming { 24346441bdcSMatt Fleming size_t len; 24446441bdcSMatt Fleming 24546441bdcSMatt Fleming len = strlen(name); 24646441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 24746441bdcSMatt Fleming return true; 24846441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 24946441bdcSMatt Fleming return true; 250044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 251044330c1SMatt Fleming return true; 2521d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 2531d9e446bSJiri Olsa return true; 25446441bdcSMatt Fleming 25546441bdcSMatt Fleming return false; 25646441bdcSMatt Fleming } 25746441bdcSMatt Fleming 258a6146d50SZheng Yan /* 259a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 260a6146d50SZheng Yan * specified in 'dir' parameter. 261a6146d50SZheng Yan */ 262a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 263a6146d50SZheng Yan { 264a6146d50SZheng Yan struct dirent *evt_ent; 265a6146d50SZheng Yan DIR *event_dir; 266a6146d50SZheng Yan int ret = 0; 267a6146d50SZheng Yan 268a6146d50SZheng Yan event_dir = opendir(dir); 269a6146d50SZheng Yan if (!event_dir) 270a6146d50SZheng Yan return -EINVAL; 271a6146d50SZheng Yan 272a6146d50SZheng Yan while (!ret && (evt_ent = readdir(event_dir))) { 273a6146d50SZheng Yan char path[PATH_MAX]; 274a6146d50SZheng Yan char *name = evt_ent->d_name; 275a6146d50SZheng Yan FILE *file; 276a6146d50SZheng Yan 277a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 278a6146d50SZheng Yan continue; 279a6146d50SZheng Yan 280410136f5SStephane Eranian /* 28146441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 282410136f5SStephane Eranian */ 28346441bdcSMatt Fleming if (pmu_alias_info_file(name)) 284410136f5SStephane Eranian continue; 285410136f5SStephane Eranian 286a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 287a6146d50SZheng Yan 288a6146d50SZheng Yan ret = -EINVAL; 289a6146d50SZheng Yan file = fopen(path, "r"); 290a6146d50SZheng Yan if (!file) 291a6146d50SZheng Yan break; 292410136f5SStephane Eranian 293410136f5SStephane Eranian ret = perf_pmu__new_alias(head, dir, name, file); 294a6146d50SZheng Yan fclose(file); 295a6146d50SZheng Yan } 296a6146d50SZheng Yan 297a6146d50SZheng Yan closedir(event_dir); 298a6146d50SZheng Yan return ret; 299a6146d50SZheng Yan } 300a6146d50SZheng Yan 301a6146d50SZheng Yan /* 302a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 303a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 304a6146d50SZheng Yan */ 305b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 306a6146d50SZheng Yan { 307a6146d50SZheng Yan struct stat st; 308a6146d50SZheng Yan char path[PATH_MAX]; 309cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 310a6146d50SZheng Yan 311a6146d50SZheng Yan if (!sysfs) 312a6146d50SZheng Yan return -1; 313a6146d50SZheng Yan 314a6146d50SZheng Yan snprintf(path, PATH_MAX, 315a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 316a6146d50SZheng Yan 317a6146d50SZheng Yan if (stat(path, &st) < 0) 3183fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 319a6146d50SZheng Yan 320a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 321a6146d50SZheng Yan return -1; 322a6146d50SZheng Yan 323a6146d50SZheng Yan return 0; 324a6146d50SZheng Yan } 325a6146d50SZheng Yan 3265c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 327a6146d50SZheng Yan struct list_head *terms) 328a6146d50SZheng Yan { 3297c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 330a6146d50SZheng Yan LIST_HEAD(list); 331a6146d50SZheng Yan int ret; 332a6146d50SZheng Yan 333a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 3347c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 335a6146d50SZheng Yan if (ret) { 336a6146d50SZheng Yan parse_events__free_terms(&list); 337a6146d50SZheng Yan return ret; 338a6146d50SZheng Yan } 3397c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 340a6146d50SZheng Yan } 341a6146d50SZheng Yan list_splice(&list, terms); 342a6146d50SZheng Yan return 0; 343a6146d50SZheng Yan } 344a6146d50SZheng Yan 345cd82a32eSJiri Olsa /* 346cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 347cd82a32eSJiri Olsa * located at: 348cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 349cd82a32eSJiri Olsa */ 350b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 351cd82a32eSJiri Olsa { 352cd82a32eSJiri Olsa struct stat st; 353cd82a32eSJiri Olsa char path[PATH_MAX]; 354cd82a32eSJiri Olsa FILE *file; 355cd82a32eSJiri Olsa int ret = 0; 356cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 357cd82a32eSJiri Olsa 358cd82a32eSJiri Olsa if (!sysfs) 359cd82a32eSJiri Olsa return -1; 360cd82a32eSJiri Olsa 361cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 36250a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 363cd82a32eSJiri Olsa 364cd82a32eSJiri Olsa if (stat(path, &st) < 0) 365cd82a32eSJiri Olsa return -1; 366cd82a32eSJiri Olsa 367cd82a32eSJiri Olsa file = fopen(path, "r"); 368cd82a32eSJiri Olsa if (!file) 369cd82a32eSJiri Olsa return -EINVAL; 370cd82a32eSJiri Olsa 371cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 372cd82a32eSJiri Olsa ret = -1; 373cd82a32eSJiri Olsa 374cd82a32eSJiri Olsa fclose(file); 375cd82a32eSJiri Olsa return ret; 376cd82a32eSJiri Olsa } 377cd82a32eSJiri Olsa 37850a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 37950a9667cSRobert Richter static void pmu_read_sysfs(void) 38050a9667cSRobert Richter { 38150a9667cSRobert Richter char path[PATH_MAX]; 38250a9667cSRobert Richter DIR *dir; 38350a9667cSRobert Richter struct dirent *dent; 384cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 38550a9667cSRobert Richter 38650a9667cSRobert Richter if (!sysfs) 38750a9667cSRobert Richter return; 38850a9667cSRobert Richter 38950a9667cSRobert Richter snprintf(path, PATH_MAX, 39050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 39150a9667cSRobert Richter 39250a9667cSRobert Richter dir = opendir(path); 39350a9667cSRobert Richter if (!dir) 39450a9667cSRobert Richter return; 39550a9667cSRobert Richter 39650a9667cSRobert Richter while ((dent = readdir(dir))) { 39750a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 39850a9667cSRobert Richter continue; 39950a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 40050a9667cSRobert Richter perf_pmu__find(dent->d_name); 40150a9667cSRobert Richter } 40250a9667cSRobert Richter 40350a9667cSRobert Richter closedir(dir); 40450a9667cSRobert Richter } 40550a9667cSRobert Richter 406b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 4077ae92e74SYan, Zheng { 4087ae92e74SYan, Zheng struct stat st; 4097ae92e74SYan, Zheng char path[PATH_MAX]; 4107ae92e74SYan, Zheng FILE *file; 4117ae92e74SYan, Zheng struct cpu_map *cpus; 412cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 4137ae92e74SYan, Zheng 4147ae92e74SYan, Zheng if (!sysfs) 4157ae92e74SYan, Zheng return NULL; 4167ae92e74SYan, Zheng 4177ae92e74SYan, Zheng snprintf(path, PATH_MAX, 4187ae92e74SYan, Zheng "%s/bus/event_source/devices/%s/cpumask", sysfs, name); 4197ae92e74SYan, Zheng 4207ae92e74SYan, Zheng if (stat(path, &st) < 0) 4217ae92e74SYan, Zheng return NULL; 4227ae92e74SYan, Zheng 4237ae92e74SYan, Zheng file = fopen(path, "r"); 4247ae92e74SYan, Zheng if (!file) 4257ae92e74SYan, Zheng return NULL; 4267ae92e74SYan, Zheng 4277ae92e74SYan, Zheng cpus = cpu_map__read(file); 4287ae92e74SYan, Zheng fclose(file); 4297ae92e74SYan, Zheng return cpus; 4307ae92e74SYan, Zheng } 4317ae92e74SYan, Zheng 432dc0a6202SAdrian Hunter struct perf_event_attr *__attribute__((weak)) 433dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 434dc0a6202SAdrian Hunter { 435dc0a6202SAdrian Hunter return NULL; 436dc0a6202SAdrian Hunter } 437dc0a6202SAdrian Hunter 438b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 439cd82a32eSJiri Olsa { 440cd82a32eSJiri Olsa struct perf_pmu *pmu; 441cd82a32eSJiri Olsa LIST_HEAD(format); 442a6146d50SZheng Yan LIST_HEAD(aliases); 443cd82a32eSJiri Olsa __u32 type; 444cd82a32eSJiri Olsa 445cd82a32eSJiri Olsa /* 446cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 447cd82a32eSJiri Olsa * type value and format definitions. Load both right 448cd82a32eSJiri Olsa * now. 449cd82a32eSJiri Olsa */ 450cd82a32eSJiri Olsa if (pmu_format(name, &format)) 451cd82a32eSJiri Olsa return NULL; 452cd82a32eSJiri Olsa 4533fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 4543fded963SJiri Olsa return NULL; 4553fded963SJiri Olsa 456cd82a32eSJiri Olsa if (pmu_type(name, &type)) 457cd82a32eSJiri Olsa return NULL; 458cd82a32eSJiri Olsa 459cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 460cd82a32eSJiri Olsa if (!pmu) 461cd82a32eSJiri Olsa return NULL; 462cd82a32eSJiri Olsa 4637ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 4647ae92e74SYan, Zheng 465cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 466a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 467cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 468a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 469cd82a32eSJiri Olsa pmu->name = strdup(name); 470cd82a32eSJiri Olsa pmu->type = type; 4719bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 472dc0a6202SAdrian Hunter 473dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 474dc0a6202SAdrian Hunter 475cd82a32eSJiri Olsa return pmu; 476cd82a32eSJiri Olsa } 477cd82a32eSJiri Olsa 478b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 479cd82a32eSJiri Olsa { 480cd82a32eSJiri Olsa struct perf_pmu *pmu; 481cd82a32eSJiri Olsa 482cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 483cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 484cd82a32eSJiri Olsa return pmu; 485cd82a32eSJiri Olsa 486cd82a32eSJiri Olsa return NULL; 487cd82a32eSJiri Olsa } 488cd82a32eSJiri Olsa 48950a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 49050a9667cSRobert Richter { 49150a9667cSRobert Richter /* 49250a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 49350a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 49450a9667cSRobert Richter */ 49550a9667cSRobert Richter if (!pmu) { 49650a9667cSRobert Richter pmu_read_sysfs(); 49750a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 49850a9667cSRobert Richter } 49950a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 50050a9667cSRobert Richter return pmu; 50150a9667cSRobert Richter return NULL; 50250a9667cSRobert Richter } 50350a9667cSRobert Richter 504b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 505cd82a32eSJiri Olsa { 506cd82a32eSJiri Olsa struct perf_pmu *pmu; 507cd82a32eSJiri Olsa 508cd82a32eSJiri Olsa /* 509cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 510cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 511cd82a32eSJiri Olsa * the pmu format definitions. 512cd82a32eSJiri Olsa */ 513cd82a32eSJiri Olsa pmu = pmu_find(name); 514cd82a32eSJiri Olsa if (pmu) 515cd82a32eSJiri Olsa return pmu; 516cd82a32eSJiri Olsa 517cd82a32eSJiri Olsa return pmu_lookup(name); 518cd82a32eSJiri Olsa } 519cd82a32eSJiri Olsa 5205c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 521cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name) 522cd82a32eSJiri Olsa { 5235c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 524cd82a32eSJiri Olsa 525cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 526cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 527cd82a32eSJiri Olsa return format; 528cd82a32eSJiri Olsa 529cd82a32eSJiri Olsa return NULL; 530cd82a32eSJiri Olsa } 531cd82a32eSJiri Olsa 532cd82a32eSJiri Olsa /* 533dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 534cd82a32eSJiri Olsa * and unformated value (value parameter). 535cd82a32eSJiri Olsa */ 536dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 537dc0a6202SAdrian Hunter bool zero) 538cd82a32eSJiri Olsa { 539cd82a32eSJiri Olsa unsigned long fbit, vbit; 540cd82a32eSJiri Olsa 541cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 542cd82a32eSJiri Olsa 543cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 544cd82a32eSJiri Olsa continue; 545cd82a32eSJiri Olsa 546dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 547dc0a6202SAdrian Hunter *v |= (1llu << fbit); 548dc0a6202SAdrian Hunter else if (zero) 549dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 550cd82a32eSJiri Olsa } 551cd82a32eSJiri Olsa } 552cd82a32eSJiri Olsa 553cd82a32eSJiri Olsa /* 554cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 55588aca8d9SCody P Schafer * user input data - term parameter. 556cd82a32eSJiri Olsa */ 557cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 558cd82a32eSJiri Olsa struct perf_event_attr *attr, 559dc0a6202SAdrian Hunter struct parse_events_term *term, 560dc0a6202SAdrian Hunter bool zero) 561cd82a32eSJiri Olsa { 5625c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 563cd82a32eSJiri Olsa __u64 *vp; 564cd82a32eSJiri Olsa 565cd82a32eSJiri Olsa /* 566cd82a32eSJiri Olsa * Support only for hardcoded and numnerial terms. 567cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 568cd82a32eSJiri Olsa * to be done for them. 569cd82a32eSJiri Olsa */ 570cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 571cd82a32eSJiri Olsa return 0; 572cd82a32eSJiri Olsa 57316fa7e82SJiri Olsa if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) 574cd82a32eSJiri Olsa return -EINVAL; 575cd82a32eSJiri Olsa 576cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 577cd82a32eSJiri Olsa if (!format) 578cd82a32eSJiri Olsa return -EINVAL; 579cd82a32eSJiri Olsa 580cd82a32eSJiri Olsa switch (format->value) { 581cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 582cd82a32eSJiri Olsa vp = &attr->config; 583cd82a32eSJiri Olsa break; 584cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 585cd82a32eSJiri Olsa vp = &attr->config1; 586cd82a32eSJiri Olsa break; 587cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 588cd82a32eSJiri Olsa vp = &attr->config2; 589cd82a32eSJiri Olsa break; 590cd82a32eSJiri Olsa default: 591cd82a32eSJiri Olsa return -EINVAL; 592cd82a32eSJiri Olsa } 593cd82a32eSJiri Olsa 59416fa7e82SJiri Olsa /* 59516fa7e82SJiri Olsa * XXX If we ever decide to go with string values for 59616fa7e82SJiri Olsa * non-hardcoded terms, here's the place to translate 59716fa7e82SJiri Olsa * them into value. 59816fa7e82SJiri Olsa */ 599dc0a6202SAdrian Hunter pmu_format_value(format->bits, term->val.num, vp, zero); 600cd82a32eSJiri Olsa return 0; 601cd82a32eSJiri Olsa } 602cd82a32eSJiri Olsa 603cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 604cff7f956SJiri Olsa struct perf_event_attr *attr, 605dc0a6202SAdrian Hunter struct list_head *head_terms, 606dc0a6202SAdrian Hunter bool zero) 607cd82a32eSJiri Olsa { 6086cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 609cd82a32eSJiri Olsa 6106b5fc39bSJiri Olsa list_for_each_entry(term, head_terms, list) 611dc0a6202SAdrian Hunter if (pmu_config_term(formats, attr, term, zero)) 612cd82a32eSJiri Olsa return -EINVAL; 613cd82a32eSJiri Olsa 614cd82a32eSJiri Olsa return 0; 615cd82a32eSJiri Olsa } 616cd82a32eSJiri Olsa 617cd82a32eSJiri Olsa /* 618cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 619cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 620cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 621cd82a32eSJiri Olsa */ 622cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 623cd82a32eSJiri Olsa struct list_head *head_terms) 624cd82a32eSJiri Olsa { 625dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 626dc0a6202SAdrian Hunter 627cd82a32eSJiri Olsa attr->type = pmu->type; 628dc0a6202SAdrian Hunter return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); 629cd82a32eSJiri Olsa } 630cd82a32eSJiri Olsa 6315c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 6326cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 633a6146d50SZheng Yan { 6345c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 635a6146d50SZheng Yan char *name; 636a6146d50SZheng Yan 637a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 638a6146d50SZheng Yan return NULL; 639a6146d50SZheng Yan 640a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 641a6146d50SZheng Yan if (term->val.num != 1) 642a6146d50SZheng Yan return NULL; 643a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 644a6146d50SZheng Yan return NULL; 645a6146d50SZheng Yan name = term->config; 646a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 647a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 648a6146d50SZheng Yan return NULL; 649a6146d50SZheng Yan name = term->val.str; 650a6146d50SZheng Yan } else { 651a6146d50SZheng Yan return NULL; 652a6146d50SZheng Yan } 653a6146d50SZheng Yan 654a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 655a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 656a6146d50SZheng Yan return alias; 657a6146d50SZheng Yan } 658a6146d50SZheng Yan return NULL; 659a6146d50SZheng Yan } 660a6146d50SZheng Yan 661410136f5SStephane Eranian 6621d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 6631d9e446bSJiri Olsa struct perf_pmu_info *info) 664410136f5SStephane Eranian { 665410136f5SStephane Eranian /* 666410136f5SStephane Eranian * Only one term in event definition can 6671d9e446bSJiri Olsa * define unit, scale and snapshot, fail 6681d9e446bSJiri Olsa * if there's more than one. 669410136f5SStephane Eranian */ 6701d9e446bSJiri Olsa if ((info->unit && alias->unit) || 6711d9e446bSJiri Olsa (info->scale && alias->scale) || 6721d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 673410136f5SStephane Eranian return -EINVAL; 674410136f5SStephane Eranian 675410136f5SStephane Eranian if (alias->unit) 6761d9e446bSJiri Olsa info->unit = alias->unit; 677410136f5SStephane Eranian 678410136f5SStephane Eranian if (alias->scale) 6791d9e446bSJiri Olsa info->scale = alias->scale; 6801d9e446bSJiri Olsa 6811d9e446bSJiri Olsa if (alias->snapshot) 6821d9e446bSJiri Olsa info->snapshot = alias->snapshot; 683410136f5SStephane Eranian 684410136f5SStephane Eranian return 0; 685410136f5SStephane Eranian } 686410136f5SStephane Eranian 687a6146d50SZheng Yan /* 688a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 689a6146d50SZheng Yan * defined for the alias 690a6146d50SZheng Yan */ 691410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 69246441bdcSMatt Fleming struct perf_pmu_info *info) 693a6146d50SZheng Yan { 6946cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 6955c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 696a6146d50SZheng Yan int ret; 697a6146d50SZheng Yan 698044330c1SMatt Fleming info->per_pkg = false; 699044330c1SMatt Fleming 7008a398897SStephane Eranian /* 7018a398897SStephane Eranian * Mark unit and scale as not set 7028a398897SStephane Eranian * (different from default values, see below) 7038a398897SStephane Eranian */ 70446441bdcSMatt Fleming info->unit = NULL; 70546441bdcSMatt Fleming info->scale = 0.0; 7061d9e446bSJiri Olsa info->snapshot = false; 707410136f5SStephane Eranian 708a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 709a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 710a6146d50SZheng Yan if (!alias) 711a6146d50SZheng Yan continue; 712a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 713a6146d50SZheng Yan if (ret) 714a6146d50SZheng Yan return ret; 715410136f5SStephane Eranian 7161d9e446bSJiri Olsa ret = check_info_data(alias, info); 717410136f5SStephane Eranian if (ret) 718410136f5SStephane Eranian return ret; 719410136f5SStephane Eranian 720044330c1SMatt Fleming if (alias->per_pkg) 721044330c1SMatt Fleming info->per_pkg = true; 722044330c1SMatt Fleming 723a6146d50SZheng Yan list_del(&term->list); 724a6146d50SZheng Yan free(term); 725a6146d50SZheng Yan } 7268a398897SStephane Eranian 7278a398897SStephane Eranian /* 7288a398897SStephane Eranian * if no unit or scale foundin aliases, then 7298a398897SStephane Eranian * set defaults as for evsel 7308a398897SStephane Eranian * unit cannot left to NULL 7318a398897SStephane Eranian */ 73246441bdcSMatt Fleming if (info->unit == NULL) 73346441bdcSMatt Fleming info->unit = ""; 7348a398897SStephane Eranian 73546441bdcSMatt Fleming if (info->scale == 0.0) 73646441bdcSMatt Fleming info->scale = 1.0; 7378a398897SStephane Eranian 738a6146d50SZheng Yan return 0; 739a6146d50SZheng Yan } 740a6146d50SZheng Yan 741cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 742cd82a32eSJiri Olsa int config, unsigned long *bits) 743cd82a32eSJiri Olsa { 7445c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 745cd82a32eSJiri Olsa 746cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 747cd82a32eSJiri Olsa if (!format) 748cd82a32eSJiri Olsa return -ENOMEM; 749cd82a32eSJiri Olsa 750cd82a32eSJiri Olsa format->name = strdup(name); 751cd82a32eSJiri Olsa format->value = config; 752cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 753cd82a32eSJiri Olsa 754cd82a32eSJiri Olsa list_add_tail(&format->list, list); 755cd82a32eSJiri Olsa return 0; 756cd82a32eSJiri Olsa } 757cd82a32eSJiri Olsa 758cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 759cd82a32eSJiri Olsa { 760cd82a32eSJiri Olsa long b; 761cd82a32eSJiri Olsa 762cd82a32eSJiri Olsa if (!to) 763cd82a32eSJiri Olsa to = from; 764cd82a32eSJiri Olsa 76515268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 766cd82a32eSJiri Olsa for (b = from; b <= to; b++) 767cd82a32eSJiri Olsa set_bit(b, bits); 768cd82a32eSJiri Olsa } 769dc098b35SAndi Kleen 770dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 771dc098b35SAndi Kleen struct perf_pmu_alias *alias) 772dc098b35SAndi Kleen { 773dc098b35SAndi Kleen snprintf(buf, len, "%s/%s/", pmu->name, alias->name); 774dc098b35SAndi Kleen return buf; 775dc098b35SAndi Kleen } 776dc098b35SAndi Kleen 777dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 778dc098b35SAndi Kleen struct perf_pmu_alias *alias) 779dc098b35SAndi Kleen { 780dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 781dc098b35SAndi Kleen return buf; 782dc098b35SAndi Kleen } 783dc098b35SAndi Kleen 784dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b) 785dc098b35SAndi Kleen { 786dc098b35SAndi Kleen const char * const *as = a; 787dc098b35SAndi Kleen const char * const *bs = b; 788dc098b35SAndi Kleen return strcmp(*as, *bs); 789dc098b35SAndi Kleen } 790dc098b35SAndi Kleen 791dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only) 792dc098b35SAndi Kleen { 793dc098b35SAndi Kleen struct perf_pmu *pmu; 794dc098b35SAndi Kleen struct perf_pmu_alias *alias; 795dc098b35SAndi Kleen char buf[1024]; 796dc098b35SAndi Kleen int printed = 0; 797dc098b35SAndi Kleen int len, j; 798dc098b35SAndi Kleen char **aliases; 799dc098b35SAndi Kleen 800dc098b35SAndi Kleen pmu = NULL; 801dc098b35SAndi Kleen len = 0; 80242634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 803dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 804dc098b35SAndi Kleen len++; 80542634bc7SAdrian Hunter if (pmu->selectable) 80642634bc7SAdrian Hunter len++; 80742634bc7SAdrian Hunter } 8087e4772dcSArnaldo Carvalho de Melo aliases = zalloc(sizeof(char *) * len); 809dc098b35SAndi Kleen if (!aliases) 8107e4772dcSArnaldo Carvalho de Melo goto out_enomem; 811dc098b35SAndi Kleen pmu = NULL; 812dc098b35SAndi Kleen j = 0; 81342634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 814dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 815dc098b35SAndi Kleen char *name = format_alias(buf, sizeof(buf), pmu, alias); 816dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 817dc098b35SAndi Kleen 818dc098b35SAndi Kleen if (event_glob != NULL && 819dc098b35SAndi Kleen !(strglobmatch(name, event_glob) || 820dc098b35SAndi Kleen (!is_cpu && strglobmatch(alias->name, 821dc098b35SAndi Kleen event_glob)))) 822dc098b35SAndi Kleen continue; 8237e4772dcSArnaldo Carvalho de Melo 824dc098b35SAndi Kleen if (is_cpu && !name_only) 8257e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 8267e4772dcSArnaldo Carvalho de Melo 8277e4772dcSArnaldo Carvalho de Melo aliases[j] = strdup(name); 8287e4772dcSArnaldo Carvalho de Melo if (aliases[j] == NULL) 8297e4772dcSArnaldo Carvalho de Melo goto out_enomem; 830dc098b35SAndi Kleen j++; 831dc098b35SAndi Kleen } 83242634bc7SAdrian Hunter if (pmu->selectable) { 8337e4772dcSArnaldo Carvalho de Melo char *s; 8347e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 8357e4772dcSArnaldo Carvalho de Melo goto out_enomem; 8367e4772dcSArnaldo Carvalho de Melo aliases[j] = s; 83742634bc7SAdrian Hunter j++; 83842634bc7SAdrian Hunter } 83942634bc7SAdrian Hunter } 840dc098b35SAndi Kleen len = j; 841dc098b35SAndi Kleen qsort(aliases, len, sizeof(char *), cmp_string); 842dc098b35SAndi Kleen for (j = 0; j < len; j++) { 843dc098b35SAndi Kleen if (name_only) { 844dc098b35SAndi Kleen printf("%s ", aliases[j]); 845dc098b35SAndi Kleen continue; 846dc098b35SAndi Kleen } 847dc098b35SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j]); 848dc098b35SAndi Kleen printed++; 849dc098b35SAndi Kleen } 850dc098b35SAndi Kleen if (printed) 851dc098b35SAndi Kleen printf("\n"); 8527e4772dcSArnaldo Carvalho de Melo out_free: 8537e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 8547e4772dcSArnaldo Carvalho de Melo zfree(&aliases[j]); 8557e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 8567e4772dcSArnaldo Carvalho de Melo return; 8577e4772dcSArnaldo Carvalho de Melo 8587e4772dcSArnaldo Carvalho de Melo out_enomem: 8597e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 8607e4772dcSArnaldo Carvalho de Melo if (aliases) 8617e4772dcSArnaldo Carvalho de Melo goto out_free; 862dc098b35SAndi Kleen } 8634cabc3d1SAndi Kleen 8644cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 8654cabc3d1SAndi Kleen { 8664cabc3d1SAndi Kleen struct perf_pmu *pmu; 8674cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 8684cabc3d1SAndi Kleen 8694cabc3d1SAndi Kleen pmu = NULL; 8704cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 8714cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 8724cabc3d1SAndi Kleen continue; 8734cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 8744cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 8754cabc3d1SAndi Kleen return true; 8764cabc3d1SAndi Kleen } 8774cabc3d1SAndi Kleen return false; 8784cabc3d1SAndi Kleen } 8797d4bdab5SAdrian Hunter 8807d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 8817d4bdab5SAdrian Hunter { 8827d4bdab5SAdrian Hunter struct stat st; 8837d4bdab5SAdrian Hunter char path[PATH_MAX]; 8847d4bdab5SAdrian Hunter const char *sysfs; 8857d4bdab5SAdrian Hunter 8867d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 8877d4bdab5SAdrian Hunter if (!sysfs) 8887d4bdab5SAdrian Hunter return NULL; 8897d4bdab5SAdrian Hunter 8907d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 8917d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 8927d4bdab5SAdrian Hunter 8937d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 8947d4bdab5SAdrian Hunter return NULL; 8957d4bdab5SAdrian Hunter 8967d4bdab5SAdrian Hunter return fopen(path, "r"); 8977d4bdab5SAdrian Hunter } 8987d4bdab5SAdrian Hunter 8997d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 9007d4bdab5SAdrian Hunter ...) 9017d4bdab5SAdrian Hunter { 9027d4bdab5SAdrian Hunter va_list args; 9037d4bdab5SAdrian Hunter FILE *file; 9047d4bdab5SAdrian Hunter int ret = EOF; 9057d4bdab5SAdrian Hunter 9067d4bdab5SAdrian Hunter va_start(args, fmt); 9077d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 9087d4bdab5SAdrian Hunter if (file) { 9097d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 9107d4bdab5SAdrian Hunter fclose(file); 9117d4bdab5SAdrian Hunter } 9127d4bdab5SAdrian Hunter va_end(args); 9137d4bdab5SAdrian Hunter return ret; 9147d4bdab5SAdrian Hunter } 915