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 184410136f5SStephane Eranian static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 185a6146d50SZheng Yan { 1865c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 187a6146d50SZheng Yan char buf[256]; 188a6146d50SZheng Yan int ret; 189a6146d50SZheng Yan 190a6146d50SZheng Yan ret = fread(buf, 1, sizeof(buf), file); 191a6146d50SZheng Yan if (ret == 0) 192a6146d50SZheng Yan return -EINVAL; 193a6146d50SZheng Yan buf[ret] = 0; 194a6146d50SZheng Yan 195a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 196a6146d50SZheng Yan if (!alias) 197a6146d50SZheng Yan return -ENOMEM; 198a6146d50SZheng Yan 199a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 200410136f5SStephane Eranian alias->scale = 1.0; 201410136f5SStephane Eranian alias->unit[0] = '\0'; 202044330c1SMatt Fleming alias->per_pkg = false; 203410136f5SStephane Eranian 204a6146d50SZheng Yan ret = parse_events_terms(&alias->terms, buf); 205a6146d50SZheng Yan if (ret) { 206a6146d50SZheng Yan free(alias); 207a6146d50SZheng Yan return ret; 208a6146d50SZheng Yan } 209a6146d50SZheng Yan 210a6146d50SZheng Yan alias->name = strdup(name); 211410136f5SStephane Eranian /* 212410136f5SStephane Eranian * load unit name and scale if available 213410136f5SStephane Eranian */ 214410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 215410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 216044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 217410136f5SStephane Eranian 218a6146d50SZheng Yan list_add_tail(&alias->list, list); 219410136f5SStephane Eranian 220a6146d50SZheng Yan return 0; 221a6146d50SZheng Yan } 222a6146d50SZheng Yan 22346441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 22446441bdcSMatt Fleming { 22546441bdcSMatt Fleming size_t len; 22646441bdcSMatt Fleming 22746441bdcSMatt Fleming len = strlen(name); 22846441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 22946441bdcSMatt Fleming return true; 23046441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 23146441bdcSMatt Fleming return true; 232044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 233044330c1SMatt Fleming return true; 23446441bdcSMatt Fleming 23546441bdcSMatt Fleming return false; 23646441bdcSMatt Fleming } 23746441bdcSMatt Fleming 238a6146d50SZheng Yan /* 239a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 240a6146d50SZheng Yan * specified in 'dir' parameter. 241a6146d50SZheng Yan */ 242a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 243a6146d50SZheng Yan { 244a6146d50SZheng Yan struct dirent *evt_ent; 245a6146d50SZheng Yan DIR *event_dir; 246a6146d50SZheng Yan int ret = 0; 247a6146d50SZheng Yan 248a6146d50SZheng Yan event_dir = opendir(dir); 249a6146d50SZheng Yan if (!event_dir) 250a6146d50SZheng Yan return -EINVAL; 251a6146d50SZheng Yan 252a6146d50SZheng Yan while (!ret && (evt_ent = readdir(event_dir))) { 253a6146d50SZheng Yan char path[PATH_MAX]; 254a6146d50SZheng Yan char *name = evt_ent->d_name; 255a6146d50SZheng Yan FILE *file; 256a6146d50SZheng Yan 257a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 258a6146d50SZheng Yan continue; 259a6146d50SZheng Yan 260410136f5SStephane Eranian /* 26146441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 262410136f5SStephane Eranian */ 26346441bdcSMatt Fleming if (pmu_alias_info_file(name)) 264410136f5SStephane Eranian continue; 265410136f5SStephane Eranian 266a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 267a6146d50SZheng Yan 268a6146d50SZheng Yan ret = -EINVAL; 269a6146d50SZheng Yan file = fopen(path, "r"); 270a6146d50SZheng Yan if (!file) 271a6146d50SZheng Yan break; 272410136f5SStephane Eranian 273410136f5SStephane Eranian ret = perf_pmu__new_alias(head, dir, name, file); 274a6146d50SZheng Yan fclose(file); 275a6146d50SZheng Yan } 276a6146d50SZheng Yan 277a6146d50SZheng Yan closedir(event_dir); 278a6146d50SZheng Yan return ret; 279a6146d50SZheng Yan } 280a6146d50SZheng Yan 281a6146d50SZheng Yan /* 282a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 283a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 284a6146d50SZheng Yan */ 285b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 286a6146d50SZheng Yan { 287a6146d50SZheng Yan struct stat st; 288a6146d50SZheng Yan char path[PATH_MAX]; 289cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 290a6146d50SZheng Yan 291a6146d50SZheng Yan if (!sysfs) 292a6146d50SZheng Yan return -1; 293a6146d50SZheng Yan 294a6146d50SZheng Yan snprintf(path, PATH_MAX, 295a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 296a6146d50SZheng Yan 297a6146d50SZheng Yan if (stat(path, &st) < 0) 2983fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 299a6146d50SZheng Yan 300a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 301a6146d50SZheng Yan return -1; 302a6146d50SZheng Yan 303a6146d50SZheng Yan return 0; 304a6146d50SZheng Yan } 305a6146d50SZheng Yan 3065c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 307a6146d50SZheng Yan struct list_head *terms) 308a6146d50SZheng Yan { 3097c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 310a6146d50SZheng Yan LIST_HEAD(list); 311a6146d50SZheng Yan int ret; 312a6146d50SZheng Yan 313a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 3147c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 315a6146d50SZheng Yan if (ret) { 316a6146d50SZheng Yan parse_events__free_terms(&list); 317a6146d50SZheng Yan return ret; 318a6146d50SZheng Yan } 3197c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 320a6146d50SZheng Yan } 321a6146d50SZheng Yan list_splice(&list, terms); 322a6146d50SZheng Yan return 0; 323a6146d50SZheng Yan } 324a6146d50SZheng Yan 325cd82a32eSJiri Olsa /* 326cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 327cd82a32eSJiri Olsa * located at: 328cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 329cd82a32eSJiri Olsa */ 330b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 331cd82a32eSJiri Olsa { 332cd82a32eSJiri Olsa struct stat st; 333cd82a32eSJiri Olsa char path[PATH_MAX]; 334cd82a32eSJiri Olsa FILE *file; 335cd82a32eSJiri Olsa int ret = 0; 336cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 337cd82a32eSJiri Olsa 338cd82a32eSJiri Olsa if (!sysfs) 339cd82a32eSJiri Olsa return -1; 340cd82a32eSJiri Olsa 341cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 34250a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 343cd82a32eSJiri Olsa 344cd82a32eSJiri Olsa if (stat(path, &st) < 0) 345cd82a32eSJiri Olsa return -1; 346cd82a32eSJiri Olsa 347cd82a32eSJiri Olsa file = fopen(path, "r"); 348cd82a32eSJiri Olsa if (!file) 349cd82a32eSJiri Olsa return -EINVAL; 350cd82a32eSJiri Olsa 351cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 352cd82a32eSJiri Olsa ret = -1; 353cd82a32eSJiri Olsa 354cd82a32eSJiri Olsa fclose(file); 355cd82a32eSJiri Olsa return ret; 356cd82a32eSJiri Olsa } 357cd82a32eSJiri Olsa 35850a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 35950a9667cSRobert Richter static void pmu_read_sysfs(void) 36050a9667cSRobert Richter { 36150a9667cSRobert Richter char path[PATH_MAX]; 36250a9667cSRobert Richter DIR *dir; 36350a9667cSRobert Richter struct dirent *dent; 364cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 36550a9667cSRobert Richter 36650a9667cSRobert Richter if (!sysfs) 36750a9667cSRobert Richter return; 36850a9667cSRobert Richter 36950a9667cSRobert Richter snprintf(path, PATH_MAX, 37050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 37150a9667cSRobert Richter 37250a9667cSRobert Richter dir = opendir(path); 37350a9667cSRobert Richter if (!dir) 37450a9667cSRobert Richter return; 37550a9667cSRobert Richter 37650a9667cSRobert Richter while ((dent = readdir(dir))) { 37750a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 37850a9667cSRobert Richter continue; 37950a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 38050a9667cSRobert Richter perf_pmu__find(dent->d_name); 38150a9667cSRobert Richter } 38250a9667cSRobert Richter 38350a9667cSRobert Richter closedir(dir); 38450a9667cSRobert Richter } 38550a9667cSRobert Richter 386b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 3877ae92e74SYan, Zheng { 3887ae92e74SYan, Zheng struct stat st; 3897ae92e74SYan, Zheng char path[PATH_MAX]; 3907ae92e74SYan, Zheng FILE *file; 3917ae92e74SYan, Zheng struct cpu_map *cpus; 392cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 3937ae92e74SYan, Zheng 3947ae92e74SYan, Zheng if (!sysfs) 3957ae92e74SYan, Zheng return NULL; 3967ae92e74SYan, Zheng 3977ae92e74SYan, Zheng snprintf(path, PATH_MAX, 3987ae92e74SYan, Zheng "%s/bus/event_source/devices/%s/cpumask", sysfs, name); 3997ae92e74SYan, Zheng 4007ae92e74SYan, Zheng if (stat(path, &st) < 0) 4017ae92e74SYan, Zheng return NULL; 4027ae92e74SYan, Zheng 4037ae92e74SYan, Zheng file = fopen(path, "r"); 4047ae92e74SYan, Zheng if (!file) 4057ae92e74SYan, Zheng return NULL; 4067ae92e74SYan, Zheng 4077ae92e74SYan, Zheng cpus = cpu_map__read(file); 4087ae92e74SYan, Zheng fclose(file); 4097ae92e74SYan, Zheng return cpus; 4107ae92e74SYan, Zheng } 4117ae92e74SYan, Zheng 412dc0a6202SAdrian Hunter struct perf_event_attr *__attribute__((weak)) 413dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 414dc0a6202SAdrian Hunter { 415dc0a6202SAdrian Hunter return NULL; 416dc0a6202SAdrian Hunter } 417dc0a6202SAdrian Hunter 418b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 419cd82a32eSJiri Olsa { 420cd82a32eSJiri Olsa struct perf_pmu *pmu; 421cd82a32eSJiri Olsa LIST_HEAD(format); 422a6146d50SZheng Yan LIST_HEAD(aliases); 423cd82a32eSJiri Olsa __u32 type; 424cd82a32eSJiri Olsa 425cd82a32eSJiri Olsa /* 426cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 427cd82a32eSJiri Olsa * type value and format definitions. Load both right 428cd82a32eSJiri Olsa * now. 429cd82a32eSJiri Olsa */ 430cd82a32eSJiri Olsa if (pmu_format(name, &format)) 431cd82a32eSJiri Olsa return NULL; 432cd82a32eSJiri Olsa 4333fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 4343fded963SJiri Olsa return NULL; 4353fded963SJiri Olsa 436cd82a32eSJiri Olsa if (pmu_type(name, &type)) 437cd82a32eSJiri Olsa return NULL; 438cd82a32eSJiri Olsa 439cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 440cd82a32eSJiri Olsa if (!pmu) 441cd82a32eSJiri Olsa return NULL; 442cd82a32eSJiri Olsa 4437ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 4447ae92e74SYan, Zheng 445cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 446a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 447cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 448a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 449cd82a32eSJiri Olsa pmu->name = strdup(name); 450cd82a32eSJiri Olsa pmu->type = type; 4519bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 452dc0a6202SAdrian Hunter 453dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 454dc0a6202SAdrian Hunter 455cd82a32eSJiri Olsa return pmu; 456cd82a32eSJiri Olsa } 457cd82a32eSJiri Olsa 458b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 459cd82a32eSJiri Olsa { 460cd82a32eSJiri Olsa struct perf_pmu *pmu; 461cd82a32eSJiri Olsa 462cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 463cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 464cd82a32eSJiri Olsa return pmu; 465cd82a32eSJiri Olsa 466cd82a32eSJiri Olsa return NULL; 467cd82a32eSJiri Olsa } 468cd82a32eSJiri Olsa 46950a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 47050a9667cSRobert Richter { 47150a9667cSRobert Richter /* 47250a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 47350a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 47450a9667cSRobert Richter */ 47550a9667cSRobert Richter if (!pmu) { 47650a9667cSRobert Richter pmu_read_sysfs(); 47750a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 47850a9667cSRobert Richter } 47950a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 48050a9667cSRobert Richter return pmu; 48150a9667cSRobert Richter return NULL; 48250a9667cSRobert Richter } 48350a9667cSRobert Richter 484b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 485cd82a32eSJiri Olsa { 486cd82a32eSJiri Olsa struct perf_pmu *pmu; 487cd82a32eSJiri Olsa 488cd82a32eSJiri Olsa /* 489cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 490cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 491cd82a32eSJiri Olsa * the pmu format definitions. 492cd82a32eSJiri Olsa */ 493cd82a32eSJiri Olsa pmu = pmu_find(name); 494cd82a32eSJiri Olsa if (pmu) 495cd82a32eSJiri Olsa return pmu; 496cd82a32eSJiri Olsa 497cd82a32eSJiri Olsa return pmu_lookup(name); 498cd82a32eSJiri Olsa } 499cd82a32eSJiri Olsa 5005c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 501cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name) 502cd82a32eSJiri Olsa { 5035c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 504cd82a32eSJiri Olsa 505cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 506cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 507cd82a32eSJiri Olsa return format; 508cd82a32eSJiri Olsa 509cd82a32eSJiri Olsa return NULL; 510cd82a32eSJiri Olsa } 511cd82a32eSJiri Olsa 512cd82a32eSJiri Olsa /* 513dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 514cd82a32eSJiri Olsa * and unformated value (value parameter). 515cd82a32eSJiri Olsa */ 516dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 517dc0a6202SAdrian Hunter bool zero) 518cd82a32eSJiri Olsa { 519cd82a32eSJiri Olsa unsigned long fbit, vbit; 520cd82a32eSJiri Olsa 521cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 522cd82a32eSJiri Olsa 523cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 524cd82a32eSJiri Olsa continue; 525cd82a32eSJiri Olsa 526dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 527dc0a6202SAdrian Hunter *v |= (1llu << fbit); 528dc0a6202SAdrian Hunter else if (zero) 529dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 530cd82a32eSJiri Olsa } 531cd82a32eSJiri Olsa } 532cd82a32eSJiri Olsa 533cd82a32eSJiri Olsa /* 534cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 53588aca8d9SCody P Schafer * user input data - term parameter. 536cd82a32eSJiri Olsa */ 537cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 538cd82a32eSJiri Olsa struct perf_event_attr *attr, 539dc0a6202SAdrian Hunter struct parse_events_term *term, 540dc0a6202SAdrian Hunter bool zero) 541cd82a32eSJiri Olsa { 5425c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 543cd82a32eSJiri Olsa __u64 *vp; 544cd82a32eSJiri Olsa 545cd82a32eSJiri Olsa /* 546cd82a32eSJiri Olsa * Support only for hardcoded and numnerial terms. 547cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 548cd82a32eSJiri Olsa * to be done for them. 549cd82a32eSJiri Olsa */ 550cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 551cd82a32eSJiri Olsa return 0; 552cd82a32eSJiri Olsa 55316fa7e82SJiri Olsa if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) 554cd82a32eSJiri Olsa return -EINVAL; 555cd82a32eSJiri Olsa 556cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 557cd82a32eSJiri Olsa if (!format) 558cd82a32eSJiri Olsa return -EINVAL; 559cd82a32eSJiri Olsa 560cd82a32eSJiri Olsa switch (format->value) { 561cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 562cd82a32eSJiri Olsa vp = &attr->config; 563cd82a32eSJiri Olsa break; 564cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 565cd82a32eSJiri Olsa vp = &attr->config1; 566cd82a32eSJiri Olsa break; 567cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 568cd82a32eSJiri Olsa vp = &attr->config2; 569cd82a32eSJiri Olsa break; 570cd82a32eSJiri Olsa default: 571cd82a32eSJiri Olsa return -EINVAL; 572cd82a32eSJiri Olsa } 573cd82a32eSJiri Olsa 57416fa7e82SJiri Olsa /* 57516fa7e82SJiri Olsa * XXX If we ever decide to go with string values for 57616fa7e82SJiri Olsa * non-hardcoded terms, here's the place to translate 57716fa7e82SJiri Olsa * them into value. 57816fa7e82SJiri Olsa */ 579dc0a6202SAdrian Hunter pmu_format_value(format->bits, term->val.num, vp, zero); 580cd82a32eSJiri Olsa return 0; 581cd82a32eSJiri Olsa } 582cd82a32eSJiri Olsa 583cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 584cff7f956SJiri Olsa struct perf_event_attr *attr, 585dc0a6202SAdrian Hunter struct list_head *head_terms, 586dc0a6202SAdrian Hunter bool zero) 587cd82a32eSJiri Olsa { 5886cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 589cd82a32eSJiri Olsa 5906b5fc39bSJiri Olsa list_for_each_entry(term, head_terms, list) 591dc0a6202SAdrian Hunter if (pmu_config_term(formats, attr, term, zero)) 592cd82a32eSJiri Olsa return -EINVAL; 593cd82a32eSJiri Olsa 594cd82a32eSJiri Olsa return 0; 595cd82a32eSJiri Olsa } 596cd82a32eSJiri Olsa 597cd82a32eSJiri Olsa /* 598cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 599cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 600cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 601cd82a32eSJiri Olsa */ 602cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 603cd82a32eSJiri Olsa struct list_head *head_terms) 604cd82a32eSJiri Olsa { 605dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 606dc0a6202SAdrian Hunter 607cd82a32eSJiri Olsa attr->type = pmu->type; 608dc0a6202SAdrian Hunter return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); 609cd82a32eSJiri Olsa } 610cd82a32eSJiri Olsa 6115c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 6126cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 613a6146d50SZheng Yan { 6145c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 615a6146d50SZheng Yan char *name; 616a6146d50SZheng Yan 617a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 618a6146d50SZheng Yan return NULL; 619a6146d50SZheng Yan 620a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 621a6146d50SZheng Yan if (term->val.num != 1) 622a6146d50SZheng Yan return NULL; 623a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 624a6146d50SZheng Yan return NULL; 625a6146d50SZheng Yan name = term->config; 626a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 627a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 628a6146d50SZheng Yan return NULL; 629a6146d50SZheng Yan name = term->val.str; 630a6146d50SZheng Yan } else { 631a6146d50SZheng Yan return NULL; 632a6146d50SZheng Yan } 633a6146d50SZheng Yan 634a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 635a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 636a6146d50SZheng Yan return alias; 637a6146d50SZheng Yan } 638a6146d50SZheng Yan return NULL; 639a6146d50SZheng Yan } 640a6146d50SZheng Yan 641410136f5SStephane Eranian 642410136f5SStephane Eranian static int check_unit_scale(struct perf_pmu_alias *alias, 6438a398897SStephane Eranian const char **unit, double *scale) 644410136f5SStephane Eranian { 645410136f5SStephane Eranian /* 646410136f5SStephane Eranian * Only one term in event definition can 647410136f5SStephane Eranian * define unit and scale, fail if there's 648410136f5SStephane Eranian * more than one. 649410136f5SStephane Eranian */ 650410136f5SStephane Eranian if ((*unit && alias->unit) || 651410136f5SStephane Eranian (*scale && alias->scale)) 652410136f5SStephane Eranian return -EINVAL; 653410136f5SStephane Eranian 654410136f5SStephane Eranian if (alias->unit) 655410136f5SStephane Eranian *unit = alias->unit; 656410136f5SStephane Eranian 657410136f5SStephane Eranian if (alias->scale) 658410136f5SStephane Eranian *scale = alias->scale; 659410136f5SStephane Eranian 660410136f5SStephane Eranian return 0; 661410136f5SStephane Eranian } 662410136f5SStephane Eranian 663a6146d50SZheng Yan /* 664a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 665a6146d50SZheng Yan * defined for the alias 666a6146d50SZheng Yan */ 667410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 66846441bdcSMatt Fleming struct perf_pmu_info *info) 669a6146d50SZheng Yan { 6706cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 6715c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 672a6146d50SZheng Yan int ret; 673a6146d50SZheng Yan 674044330c1SMatt Fleming info->per_pkg = false; 675044330c1SMatt Fleming 6768a398897SStephane Eranian /* 6778a398897SStephane Eranian * Mark unit and scale as not set 6788a398897SStephane Eranian * (different from default values, see below) 6798a398897SStephane Eranian */ 68046441bdcSMatt Fleming info->unit = NULL; 68146441bdcSMatt Fleming info->scale = 0.0; 682410136f5SStephane Eranian 683a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 684a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 685a6146d50SZheng Yan if (!alias) 686a6146d50SZheng Yan continue; 687a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 688a6146d50SZheng Yan if (ret) 689a6146d50SZheng Yan return ret; 690410136f5SStephane Eranian 69146441bdcSMatt Fleming ret = check_unit_scale(alias, &info->unit, &info->scale); 692410136f5SStephane Eranian if (ret) 693410136f5SStephane Eranian return ret; 694410136f5SStephane Eranian 695044330c1SMatt Fleming if (alias->per_pkg) 696044330c1SMatt Fleming info->per_pkg = true; 697044330c1SMatt Fleming 698a6146d50SZheng Yan list_del(&term->list); 699a6146d50SZheng Yan free(term); 700a6146d50SZheng Yan } 7018a398897SStephane Eranian 7028a398897SStephane Eranian /* 7038a398897SStephane Eranian * if no unit or scale foundin aliases, then 7048a398897SStephane Eranian * set defaults as for evsel 7058a398897SStephane Eranian * unit cannot left to NULL 7068a398897SStephane Eranian */ 70746441bdcSMatt Fleming if (info->unit == NULL) 70846441bdcSMatt Fleming info->unit = ""; 7098a398897SStephane Eranian 71046441bdcSMatt Fleming if (info->scale == 0.0) 71146441bdcSMatt Fleming info->scale = 1.0; 7128a398897SStephane Eranian 713a6146d50SZheng Yan return 0; 714a6146d50SZheng Yan } 715a6146d50SZheng Yan 716cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 717cd82a32eSJiri Olsa int config, unsigned long *bits) 718cd82a32eSJiri Olsa { 7195c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 720cd82a32eSJiri Olsa 721cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 722cd82a32eSJiri Olsa if (!format) 723cd82a32eSJiri Olsa return -ENOMEM; 724cd82a32eSJiri Olsa 725cd82a32eSJiri Olsa format->name = strdup(name); 726cd82a32eSJiri Olsa format->value = config; 727cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 728cd82a32eSJiri Olsa 729cd82a32eSJiri Olsa list_add_tail(&format->list, list); 730cd82a32eSJiri Olsa return 0; 731cd82a32eSJiri Olsa } 732cd82a32eSJiri Olsa 733cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 734cd82a32eSJiri Olsa { 735cd82a32eSJiri Olsa long b; 736cd82a32eSJiri Olsa 737cd82a32eSJiri Olsa if (!to) 738cd82a32eSJiri Olsa to = from; 739cd82a32eSJiri Olsa 74015268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 741cd82a32eSJiri Olsa for (b = from; b <= to; b++) 742cd82a32eSJiri Olsa set_bit(b, bits); 743cd82a32eSJiri Olsa } 744dc098b35SAndi Kleen 745dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 746dc098b35SAndi Kleen struct perf_pmu_alias *alias) 747dc098b35SAndi Kleen { 748dc098b35SAndi Kleen snprintf(buf, len, "%s/%s/", pmu->name, alias->name); 749dc098b35SAndi Kleen return buf; 750dc098b35SAndi Kleen } 751dc098b35SAndi Kleen 752dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 753dc098b35SAndi Kleen struct perf_pmu_alias *alias) 754dc098b35SAndi Kleen { 755dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 756dc098b35SAndi Kleen return buf; 757dc098b35SAndi Kleen } 758dc098b35SAndi Kleen 759dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b) 760dc098b35SAndi Kleen { 761dc098b35SAndi Kleen const char * const *as = a; 762dc098b35SAndi Kleen const char * const *bs = b; 763dc098b35SAndi Kleen return strcmp(*as, *bs); 764dc098b35SAndi Kleen } 765dc098b35SAndi Kleen 766dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only) 767dc098b35SAndi Kleen { 768dc098b35SAndi Kleen struct perf_pmu *pmu; 769dc098b35SAndi Kleen struct perf_pmu_alias *alias; 770dc098b35SAndi Kleen char buf[1024]; 771dc098b35SAndi Kleen int printed = 0; 772dc098b35SAndi Kleen int len, j; 773dc098b35SAndi Kleen char **aliases; 774dc098b35SAndi Kleen 775dc098b35SAndi Kleen pmu = NULL; 776dc098b35SAndi Kleen len = 0; 77742634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 778dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 779dc098b35SAndi Kleen len++; 78042634bc7SAdrian Hunter if (pmu->selectable) 78142634bc7SAdrian Hunter len++; 78242634bc7SAdrian Hunter } 7837e4772dcSArnaldo Carvalho de Melo aliases = zalloc(sizeof(char *) * len); 784dc098b35SAndi Kleen if (!aliases) 7857e4772dcSArnaldo Carvalho de Melo goto out_enomem; 786dc098b35SAndi Kleen pmu = NULL; 787dc098b35SAndi Kleen j = 0; 78842634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 789dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 790dc098b35SAndi Kleen char *name = format_alias(buf, sizeof(buf), pmu, alias); 791dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 792dc098b35SAndi Kleen 793dc098b35SAndi Kleen if (event_glob != NULL && 794dc098b35SAndi Kleen !(strglobmatch(name, event_glob) || 795dc098b35SAndi Kleen (!is_cpu && strglobmatch(alias->name, 796dc098b35SAndi Kleen event_glob)))) 797dc098b35SAndi Kleen continue; 7987e4772dcSArnaldo Carvalho de Melo 799dc098b35SAndi Kleen if (is_cpu && !name_only) 8007e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 8017e4772dcSArnaldo Carvalho de Melo 8027e4772dcSArnaldo Carvalho de Melo aliases[j] = strdup(name); 8037e4772dcSArnaldo Carvalho de Melo if (aliases[j] == NULL) 8047e4772dcSArnaldo Carvalho de Melo goto out_enomem; 805dc098b35SAndi Kleen j++; 806dc098b35SAndi Kleen } 80742634bc7SAdrian Hunter if (pmu->selectable) { 8087e4772dcSArnaldo Carvalho de Melo char *s; 8097e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 8107e4772dcSArnaldo Carvalho de Melo goto out_enomem; 8117e4772dcSArnaldo Carvalho de Melo aliases[j] = s; 81242634bc7SAdrian Hunter j++; 81342634bc7SAdrian Hunter } 81442634bc7SAdrian Hunter } 815dc098b35SAndi Kleen len = j; 816dc098b35SAndi Kleen qsort(aliases, len, sizeof(char *), cmp_string); 817dc098b35SAndi Kleen for (j = 0; j < len; j++) { 818dc098b35SAndi Kleen if (name_only) { 819dc098b35SAndi Kleen printf("%s ", aliases[j]); 820dc098b35SAndi Kleen continue; 821dc098b35SAndi Kleen } 822dc098b35SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j]); 823dc098b35SAndi Kleen printed++; 824dc098b35SAndi Kleen } 825dc098b35SAndi Kleen if (printed) 826dc098b35SAndi Kleen printf("\n"); 8277e4772dcSArnaldo Carvalho de Melo out_free: 8287e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 8297e4772dcSArnaldo Carvalho de Melo zfree(&aliases[j]); 8307e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 8317e4772dcSArnaldo Carvalho de Melo return; 8327e4772dcSArnaldo Carvalho de Melo 8337e4772dcSArnaldo Carvalho de Melo out_enomem: 8347e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 8357e4772dcSArnaldo Carvalho de Melo if (aliases) 8367e4772dcSArnaldo Carvalho de Melo goto out_free; 837dc098b35SAndi Kleen } 8384cabc3d1SAndi Kleen 8394cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 8404cabc3d1SAndi Kleen { 8414cabc3d1SAndi Kleen struct perf_pmu *pmu; 8424cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 8434cabc3d1SAndi Kleen 8444cabc3d1SAndi Kleen pmu = NULL; 8454cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 8464cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 8474cabc3d1SAndi Kleen continue; 8484cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 8494cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 8504cabc3d1SAndi Kleen return true; 8514cabc3d1SAndi Kleen } 8524cabc3d1SAndi Kleen return false; 8534cabc3d1SAndi Kleen } 8547d4bdab5SAdrian Hunter 8557d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 8567d4bdab5SAdrian Hunter { 8577d4bdab5SAdrian Hunter struct stat st; 8587d4bdab5SAdrian Hunter char path[PATH_MAX]; 8597d4bdab5SAdrian Hunter const char *sysfs; 8607d4bdab5SAdrian Hunter 8617d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 8627d4bdab5SAdrian Hunter if (!sysfs) 8637d4bdab5SAdrian Hunter return NULL; 8647d4bdab5SAdrian Hunter 8657d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 8667d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 8677d4bdab5SAdrian Hunter 8687d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 8697d4bdab5SAdrian Hunter return NULL; 8707d4bdab5SAdrian Hunter 8717d4bdab5SAdrian Hunter return fopen(path, "r"); 8727d4bdab5SAdrian Hunter } 8737d4bdab5SAdrian Hunter 8747d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 8757d4bdab5SAdrian Hunter ...) 8767d4bdab5SAdrian Hunter { 8777d4bdab5SAdrian Hunter va_list args; 8787d4bdab5SAdrian Hunter FILE *file; 8797d4bdab5SAdrian Hunter int ret = EOF; 8807d4bdab5SAdrian Hunter 8817d4bdab5SAdrian Hunter va_start(args, fmt); 8827d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 8837d4bdab5SAdrian Hunter if (file) { 8847d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 8857d4bdab5SAdrian Hunter fclose(file); 8867d4bdab5SAdrian Hunter } 8877d4bdab5SAdrian Hunter va_end(args); 8887d4bdab5SAdrian Hunter return ret; 8897d4bdab5SAdrian Hunter } 890