1cd82a32eSJiri Olsa #include <linux/list.h> 2cd82a32eSJiri Olsa #include <sys/types.h> 3cd82a32eSJiri Olsa #include <sys/stat.h> 4cd82a32eSJiri Olsa #include <unistd.h> 5cd82a32eSJiri Olsa #include <stdio.h> 6cd82a32eSJiri Olsa #include <dirent.h> 7cd82a32eSJiri Olsa #include "sysfs.h" 8cd82a32eSJiri Olsa #include "util.h" 9cd82a32eSJiri Olsa #include "pmu.h" 10cd82a32eSJiri Olsa #include "parse-events.h" 117ae92e74SYan, Zheng #include "cpumap.h" 12cd82a32eSJiri Olsa 13ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_alias { 14ab1bf653SArnaldo Carvalho de Melo char *name; 15ab1bf653SArnaldo Carvalho de Melo struct list_head terms; 16ab1bf653SArnaldo Carvalho de Melo struct list_head list; 17ab1bf653SArnaldo Carvalho de Melo }; 18ab1bf653SArnaldo Carvalho de Melo 19ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 20ab1bf653SArnaldo Carvalho de Melo char *name; 21ab1bf653SArnaldo Carvalho de Melo int value; 22ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 23ab1bf653SArnaldo Carvalho de Melo struct list_head list; 24ab1bf653SArnaldo Carvalho de Melo }; 25ab1bf653SArnaldo Carvalho de Melo 2650a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 2750a9667cSRobert Richter 28cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 29cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 30cd82a32eSJiri Olsa 31cd82a32eSJiri Olsa static LIST_HEAD(pmus); 32cd82a32eSJiri Olsa 33cd82a32eSJiri Olsa /* 34cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 35cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 36cd82a32eSJiri Olsa */ 37cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 38cd82a32eSJiri Olsa { 39cd82a32eSJiri Olsa struct dirent *evt_ent; 40cd82a32eSJiri Olsa DIR *format_dir; 41cd82a32eSJiri Olsa int ret = 0; 42cd82a32eSJiri Olsa 43cd82a32eSJiri Olsa format_dir = opendir(dir); 44cd82a32eSJiri Olsa if (!format_dir) 45cd82a32eSJiri Olsa return -EINVAL; 46cd82a32eSJiri Olsa 47cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 48cd82a32eSJiri Olsa char path[PATH_MAX]; 49cd82a32eSJiri Olsa char *name = evt_ent->d_name; 50cd82a32eSJiri Olsa FILE *file; 51cd82a32eSJiri Olsa 52cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 53cd82a32eSJiri Olsa continue; 54cd82a32eSJiri Olsa 55cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 56cd82a32eSJiri Olsa 57cd82a32eSJiri Olsa ret = -EINVAL; 58cd82a32eSJiri Olsa file = fopen(path, "r"); 59cd82a32eSJiri Olsa if (!file) 60cd82a32eSJiri Olsa break; 61cd82a32eSJiri Olsa 62cd82a32eSJiri Olsa perf_pmu_in = file; 63cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 64cd82a32eSJiri Olsa fclose(file); 65cd82a32eSJiri Olsa } 66cd82a32eSJiri Olsa 67cd82a32eSJiri Olsa closedir(format_dir); 68cd82a32eSJiri Olsa return ret; 69cd82a32eSJiri Olsa } 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa /* 72cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 73cd82a32eSJiri Olsa * located at: 74cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 75cd82a32eSJiri Olsa */ 76b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 77cd82a32eSJiri Olsa { 78cd82a32eSJiri Olsa struct stat st; 79cd82a32eSJiri Olsa char path[PATH_MAX]; 80cd82a32eSJiri Olsa const char *sysfs; 81cd82a32eSJiri Olsa 82cd82a32eSJiri Olsa sysfs = sysfs_find_mountpoint(); 83cd82a32eSJiri Olsa if (!sysfs) 84cd82a32eSJiri Olsa return -1; 85cd82a32eSJiri Olsa 86cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 8750a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 88cd82a32eSJiri Olsa 89cd82a32eSJiri Olsa if (stat(path, &st) < 0) 909bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 91cd82a32eSJiri Olsa 92cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 93cd82a32eSJiri Olsa return -1; 94cd82a32eSJiri Olsa 95cd82a32eSJiri Olsa return 0; 96cd82a32eSJiri Olsa } 97cd82a32eSJiri Olsa 98a6146d50SZheng Yan static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 99a6146d50SZheng Yan { 1005c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 101a6146d50SZheng Yan char buf[256]; 102a6146d50SZheng Yan int ret; 103a6146d50SZheng Yan 104a6146d50SZheng Yan ret = fread(buf, 1, sizeof(buf), file); 105a6146d50SZheng Yan if (ret == 0) 106a6146d50SZheng Yan return -EINVAL; 107a6146d50SZheng Yan buf[ret] = 0; 108a6146d50SZheng Yan 109a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 110a6146d50SZheng Yan if (!alias) 111a6146d50SZheng Yan return -ENOMEM; 112a6146d50SZheng Yan 113a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 114a6146d50SZheng Yan ret = parse_events_terms(&alias->terms, buf); 115a6146d50SZheng Yan if (ret) { 116a6146d50SZheng Yan free(alias); 117a6146d50SZheng Yan return ret; 118a6146d50SZheng Yan } 119a6146d50SZheng Yan 120a6146d50SZheng Yan alias->name = strdup(name); 121a6146d50SZheng Yan list_add_tail(&alias->list, list); 122a6146d50SZheng Yan return 0; 123a6146d50SZheng Yan } 124a6146d50SZheng Yan 125a6146d50SZheng Yan /* 126a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 127a6146d50SZheng Yan * specified in 'dir' parameter. 128a6146d50SZheng Yan */ 129a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 130a6146d50SZheng Yan { 131a6146d50SZheng Yan struct dirent *evt_ent; 132a6146d50SZheng Yan DIR *event_dir; 133a6146d50SZheng Yan int ret = 0; 134a6146d50SZheng Yan 135a6146d50SZheng Yan event_dir = opendir(dir); 136a6146d50SZheng Yan if (!event_dir) 137a6146d50SZheng Yan return -EINVAL; 138a6146d50SZheng Yan 139a6146d50SZheng Yan while (!ret && (evt_ent = readdir(event_dir))) { 140a6146d50SZheng Yan char path[PATH_MAX]; 141a6146d50SZheng Yan char *name = evt_ent->d_name; 142a6146d50SZheng Yan FILE *file; 143a6146d50SZheng Yan 144a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 145a6146d50SZheng Yan continue; 146a6146d50SZheng Yan 147a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 148a6146d50SZheng Yan 149a6146d50SZheng Yan ret = -EINVAL; 150a6146d50SZheng Yan file = fopen(path, "r"); 151a6146d50SZheng Yan if (!file) 152a6146d50SZheng Yan break; 153a6146d50SZheng Yan ret = perf_pmu__new_alias(head, name, file); 154a6146d50SZheng Yan fclose(file); 155a6146d50SZheng Yan } 156a6146d50SZheng Yan 157a6146d50SZheng Yan closedir(event_dir); 158a6146d50SZheng Yan return ret; 159a6146d50SZheng Yan } 160a6146d50SZheng Yan 161a6146d50SZheng Yan /* 162a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 163a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 164a6146d50SZheng Yan */ 165b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 166a6146d50SZheng Yan { 167a6146d50SZheng Yan struct stat st; 168a6146d50SZheng Yan char path[PATH_MAX]; 169a6146d50SZheng Yan const char *sysfs; 170a6146d50SZheng Yan 171a6146d50SZheng Yan sysfs = sysfs_find_mountpoint(); 172a6146d50SZheng Yan if (!sysfs) 173a6146d50SZheng Yan return -1; 174a6146d50SZheng Yan 175a6146d50SZheng Yan snprintf(path, PATH_MAX, 176a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 177a6146d50SZheng Yan 178a6146d50SZheng Yan if (stat(path, &st) < 0) 1793fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 180a6146d50SZheng Yan 181a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 182a6146d50SZheng Yan return -1; 183a6146d50SZheng Yan 184a6146d50SZheng Yan return 0; 185a6146d50SZheng Yan } 186a6146d50SZheng Yan 1875c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 188a6146d50SZheng Yan struct list_head *terms) 189a6146d50SZheng Yan { 1906cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *clone; 191a6146d50SZheng Yan LIST_HEAD(list); 192a6146d50SZheng Yan int ret; 193a6146d50SZheng Yan 194a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 1956cee6cd3SArnaldo Carvalho de Melo ret = parse_events_term__clone(&clone, term); 196a6146d50SZheng Yan if (ret) { 197a6146d50SZheng Yan parse_events__free_terms(&list); 198a6146d50SZheng Yan return ret; 199a6146d50SZheng Yan } 200a6146d50SZheng Yan list_add_tail(&clone->list, &list); 201a6146d50SZheng Yan } 202a6146d50SZheng Yan list_splice(&list, terms); 203a6146d50SZheng Yan return 0; 204a6146d50SZheng Yan } 205a6146d50SZheng Yan 206cd82a32eSJiri Olsa /* 207cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 208cd82a32eSJiri Olsa * located at: 209cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 210cd82a32eSJiri Olsa */ 211b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 212cd82a32eSJiri Olsa { 213cd82a32eSJiri Olsa struct stat st; 214cd82a32eSJiri Olsa char path[PATH_MAX]; 215cd82a32eSJiri Olsa const char *sysfs; 216cd82a32eSJiri Olsa FILE *file; 217cd82a32eSJiri Olsa int ret = 0; 218cd82a32eSJiri Olsa 219cd82a32eSJiri Olsa sysfs = sysfs_find_mountpoint(); 220cd82a32eSJiri Olsa if (!sysfs) 221cd82a32eSJiri Olsa return -1; 222cd82a32eSJiri Olsa 223cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 22450a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 225cd82a32eSJiri Olsa 226cd82a32eSJiri Olsa if (stat(path, &st) < 0) 227cd82a32eSJiri Olsa return -1; 228cd82a32eSJiri Olsa 229cd82a32eSJiri Olsa file = fopen(path, "r"); 230cd82a32eSJiri Olsa if (!file) 231cd82a32eSJiri Olsa return -EINVAL; 232cd82a32eSJiri Olsa 233cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 234cd82a32eSJiri Olsa ret = -1; 235cd82a32eSJiri Olsa 236cd82a32eSJiri Olsa fclose(file); 237cd82a32eSJiri Olsa return ret; 238cd82a32eSJiri Olsa } 239cd82a32eSJiri Olsa 24050a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 24150a9667cSRobert Richter static void pmu_read_sysfs(void) 24250a9667cSRobert Richter { 24350a9667cSRobert Richter char path[PATH_MAX]; 24450a9667cSRobert Richter const char *sysfs; 24550a9667cSRobert Richter DIR *dir; 24650a9667cSRobert Richter struct dirent *dent; 24750a9667cSRobert Richter 24850a9667cSRobert Richter sysfs = sysfs_find_mountpoint(); 24950a9667cSRobert Richter if (!sysfs) 25050a9667cSRobert Richter return; 25150a9667cSRobert Richter 25250a9667cSRobert Richter snprintf(path, PATH_MAX, 25350a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 25450a9667cSRobert Richter 25550a9667cSRobert Richter dir = opendir(path); 25650a9667cSRobert Richter if (!dir) 25750a9667cSRobert Richter return; 25850a9667cSRobert Richter 25950a9667cSRobert Richter while ((dent = readdir(dir))) { 26050a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 26150a9667cSRobert Richter continue; 26250a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 26350a9667cSRobert Richter perf_pmu__find(dent->d_name); 26450a9667cSRobert Richter } 26550a9667cSRobert Richter 26650a9667cSRobert Richter closedir(dir); 26750a9667cSRobert Richter } 26850a9667cSRobert Richter 269b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 2707ae92e74SYan, Zheng { 2717ae92e74SYan, Zheng struct stat st; 2727ae92e74SYan, Zheng char path[PATH_MAX]; 2737ae92e74SYan, Zheng const char *sysfs; 2747ae92e74SYan, Zheng FILE *file; 2757ae92e74SYan, Zheng struct cpu_map *cpus; 2767ae92e74SYan, Zheng 2777ae92e74SYan, Zheng sysfs = sysfs_find_mountpoint(); 2787ae92e74SYan, Zheng if (!sysfs) 2797ae92e74SYan, Zheng return NULL; 2807ae92e74SYan, Zheng 2817ae92e74SYan, Zheng snprintf(path, PATH_MAX, 2827ae92e74SYan, Zheng "%s/bus/event_source/devices/%s/cpumask", sysfs, name); 2837ae92e74SYan, Zheng 2847ae92e74SYan, Zheng if (stat(path, &st) < 0) 2857ae92e74SYan, Zheng return NULL; 2867ae92e74SYan, Zheng 2877ae92e74SYan, Zheng file = fopen(path, "r"); 2887ae92e74SYan, Zheng if (!file) 2897ae92e74SYan, Zheng return NULL; 2907ae92e74SYan, Zheng 2917ae92e74SYan, Zheng cpus = cpu_map__read(file); 2927ae92e74SYan, Zheng fclose(file); 2937ae92e74SYan, Zheng return cpus; 2947ae92e74SYan, Zheng } 2957ae92e74SYan, Zheng 296b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 297cd82a32eSJiri Olsa { 298cd82a32eSJiri Olsa struct perf_pmu *pmu; 299cd82a32eSJiri Olsa LIST_HEAD(format); 300a6146d50SZheng Yan LIST_HEAD(aliases); 301cd82a32eSJiri Olsa __u32 type; 302cd82a32eSJiri Olsa 303cd82a32eSJiri Olsa /* 304cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 305cd82a32eSJiri Olsa * type value and format definitions. Load both right 306cd82a32eSJiri Olsa * now. 307cd82a32eSJiri Olsa */ 308cd82a32eSJiri Olsa if (pmu_format(name, &format)) 309cd82a32eSJiri Olsa return NULL; 310cd82a32eSJiri Olsa 3113fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 3123fded963SJiri Olsa return NULL; 3133fded963SJiri Olsa 314cd82a32eSJiri Olsa if (pmu_type(name, &type)) 315cd82a32eSJiri Olsa return NULL; 316cd82a32eSJiri Olsa 317cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 318cd82a32eSJiri Olsa if (!pmu) 319cd82a32eSJiri Olsa return NULL; 320cd82a32eSJiri Olsa 3217ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 3227ae92e74SYan, Zheng 323cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 324a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 325cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 326a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 327cd82a32eSJiri Olsa pmu->name = strdup(name); 328cd82a32eSJiri Olsa pmu->type = type; 3299bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 330cd82a32eSJiri Olsa return pmu; 331cd82a32eSJiri Olsa } 332cd82a32eSJiri Olsa 333b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 334cd82a32eSJiri Olsa { 335cd82a32eSJiri Olsa struct perf_pmu *pmu; 336cd82a32eSJiri Olsa 337cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 338cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 339cd82a32eSJiri Olsa return pmu; 340cd82a32eSJiri Olsa 341cd82a32eSJiri Olsa return NULL; 342cd82a32eSJiri Olsa } 343cd82a32eSJiri Olsa 34450a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 34550a9667cSRobert Richter { 34650a9667cSRobert Richter /* 34750a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 34850a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 34950a9667cSRobert Richter */ 35050a9667cSRobert Richter if (!pmu) { 35150a9667cSRobert Richter pmu_read_sysfs(); 35250a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 35350a9667cSRobert Richter } 35450a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 35550a9667cSRobert Richter return pmu; 35650a9667cSRobert Richter return NULL; 35750a9667cSRobert Richter } 35850a9667cSRobert Richter 359b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 360cd82a32eSJiri Olsa { 361cd82a32eSJiri Olsa struct perf_pmu *pmu; 362cd82a32eSJiri Olsa 363cd82a32eSJiri Olsa /* 364cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 365cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 366cd82a32eSJiri Olsa * the pmu format definitions. 367cd82a32eSJiri Olsa */ 368cd82a32eSJiri Olsa pmu = pmu_find(name); 369cd82a32eSJiri Olsa if (pmu) 370cd82a32eSJiri Olsa return pmu; 371cd82a32eSJiri Olsa 372cd82a32eSJiri Olsa return pmu_lookup(name); 373cd82a32eSJiri Olsa } 374cd82a32eSJiri Olsa 3755c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 376cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name) 377cd82a32eSJiri Olsa { 3785c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 379cd82a32eSJiri Olsa 380cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 381cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 382cd82a32eSJiri Olsa return format; 383cd82a32eSJiri Olsa 384cd82a32eSJiri Olsa return NULL; 385cd82a32eSJiri Olsa } 386cd82a32eSJiri Olsa 387cd82a32eSJiri Olsa /* 388cd82a32eSJiri Olsa * Returns value based on the format definition (format parameter) 389cd82a32eSJiri Olsa * and unformated value (value parameter). 390cd82a32eSJiri Olsa * 391cd82a32eSJiri Olsa * TODO maybe optimize a little ;) 392cd82a32eSJiri Olsa */ 393cd82a32eSJiri Olsa static __u64 pmu_format_value(unsigned long *format, __u64 value) 394cd82a32eSJiri Olsa { 395cd82a32eSJiri Olsa unsigned long fbit, vbit; 396cd82a32eSJiri Olsa __u64 v = 0; 397cd82a32eSJiri Olsa 398cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 399cd82a32eSJiri Olsa 400cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 401cd82a32eSJiri Olsa continue; 402cd82a32eSJiri Olsa 403cd82a32eSJiri Olsa if (!(value & (1llu << vbit++))) 404cd82a32eSJiri Olsa continue; 405cd82a32eSJiri Olsa 406cd82a32eSJiri Olsa v |= (1llu << fbit); 407cd82a32eSJiri Olsa } 408cd82a32eSJiri Olsa 409cd82a32eSJiri Olsa return v; 410cd82a32eSJiri Olsa } 411cd82a32eSJiri Olsa 412cd82a32eSJiri Olsa /* 413cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 414cd82a32eSJiri Olsa * user input data - temr parameter. 415cd82a32eSJiri Olsa */ 416cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 417cd82a32eSJiri Olsa struct perf_event_attr *attr, 4186cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 419cd82a32eSJiri Olsa { 4205c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 421cd82a32eSJiri Olsa __u64 *vp; 422cd82a32eSJiri Olsa 423cd82a32eSJiri Olsa /* 424cd82a32eSJiri Olsa * Support only for hardcoded and numnerial terms. 425cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 426cd82a32eSJiri Olsa * to be done for them. 427cd82a32eSJiri Olsa */ 428cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 429cd82a32eSJiri Olsa return 0; 430cd82a32eSJiri Olsa 43116fa7e82SJiri Olsa if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) 432cd82a32eSJiri Olsa return -EINVAL; 433cd82a32eSJiri Olsa 434cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 435cd82a32eSJiri Olsa if (!format) 436cd82a32eSJiri Olsa return -EINVAL; 437cd82a32eSJiri Olsa 438cd82a32eSJiri Olsa switch (format->value) { 439cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 440cd82a32eSJiri Olsa vp = &attr->config; 441cd82a32eSJiri Olsa break; 442cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 443cd82a32eSJiri Olsa vp = &attr->config1; 444cd82a32eSJiri Olsa break; 445cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 446cd82a32eSJiri Olsa vp = &attr->config2; 447cd82a32eSJiri Olsa break; 448cd82a32eSJiri Olsa default: 449cd82a32eSJiri Olsa return -EINVAL; 450cd82a32eSJiri Olsa } 451cd82a32eSJiri Olsa 45216fa7e82SJiri Olsa /* 45316fa7e82SJiri Olsa * XXX If we ever decide to go with string values for 45416fa7e82SJiri Olsa * non-hardcoded terms, here's the place to translate 45516fa7e82SJiri Olsa * them into value. 45616fa7e82SJiri Olsa */ 457cd82a32eSJiri Olsa *vp |= pmu_format_value(format->bits, term->val.num); 458cd82a32eSJiri Olsa return 0; 459cd82a32eSJiri Olsa } 460cd82a32eSJiri Olsa 461cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 462cff7f956SJiri Olsa struct perf_event_attr *attr, 463cd82a32eSJiri Olsa struct list_head *head_terms) 464cd82a32eSJiri Olsa { 4656cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 466cd82a32eSJiri Olsa 4676b5fc39bSJiri Olsa list_for_each_entry(term, head_terms, list) 468cd82a32eSJiri Olsa if (pmu_config_term(formats, attr, term)) 469cd82a32eSJiri Olsa return -EINVAL; 470cd82a32eSJiri Olsa 471cd82a32eSJiri Olsa return 0; 472cd82a32eSJiri Olsa } 473cd82a32eSJiri Olsa 474cd82a32eSJiri Olsa /* 475cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 476cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 477cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 478cd82a32eSJiri Olsa */ 479cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 480cd82a32eSJiri Olsa struct list_head *head_terms) 481cd82a32eSJiri Olsa { 482cd82a32eSJiri Olsa attr->type = pmu->type; 483cff7f956SJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms); 484cd82a32eSJiri Olsa } 485cd82a32eSJiri Olsa 4865c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 4876cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 488a6146d50SZheng Yan { 4895c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 490a6146d50SZheng Yan char *name; 491a6146d50SZheng Yan 492a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 493a6146d50SZheng Yan return NULL; 494a6146d50SZheng Yan 495a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 496a6146d50SZheng Yan if (term->val.num != 1) 497a6146d50SZheng Yan return NULL; 498a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 499a6146d50SZheng Yan return NULL; 500a6146d50SZheng Yan name = term->config; 501a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 502a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 503a6146d50SZheng Yan return NULL; 504a6146d50SZheng Yan name = term->val.str; 505a6146d50SZheng Yan } else { 506a6146d50SZheng Yan return NULL; 507a6146d50SZheng Yan } 508a6146d50SZheng Yan 509a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 510a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 511a6146d50SZheng Yan return alias; 512a6146d50SZheng Yan } 513a6146d50SZheng Yan return NULL; 514a6146d50SZheng Yan } 515a6146d50SZheng Yan 516a6146d50SZheng Yan /* 517a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 518a6146d50SZheng Yan * defined for the alias 519a6146d50SZheng Yan */ 520a6146d50SZheng Yan int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 521a6146d50SZheng Yan { 5226cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 5235c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 524a6146d50SZheng Yan int ret; 525a6146d50SZheng Yan 526a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 527a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 528a6146d50SZheng Yan if (!alias) 529a6146d50SZheng Yan continue; 530a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 531a6146d50SZheng Yan if (ret) 532a6146d50SZheng Yan return ret; 533a6146d50SZheng Yan list_del(&term->list); 534a6146d50SZheng Yan free(term); 535a6146d50SZheng Yan } 536a6146d50SZheng Yan return 0; 537a6146d50SZheng Yan } 538a6146d50SZheng Yan 539cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 540cd82a32eSJiri Olsa int config, unsigned long *bits) 541cd82a32eSJiri Olsa { 5425c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 543cd82a32eSJiri Olsa 544cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 545cd82a32eSJiri Olsa if (!format) 546cd82a32eSJiri Olsa return -ENOMEM; 547cd82a32eSJiri Olsa 548cd82a32eSJiri Olsa format->name = strdup(name); 549cd82a32eSJiri Olsa format->value = config; 550cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 551cd82a32eSJiri Olsa 552cd82a32eSJiri Olsa list_add_tail(&format->list, list); 553cd82a32eSJiri Olsa return 0; 554cd82a32eSJiri Olsa } 555cd82a32eSJiri Olsa 556cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 557cd82a32eSJiri Olsa { 558cd82a32eSJiri Olsa long b; 559cd82a32eSJiri Olsa 560cd82a32eSJiri Olsa if (!to) 561cd82a32eSJiri Olsa to = from; 562cd82a32eSJiri Olsa 56315268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 564cd82a32eSJiri Olsa for (b = from; b <= to; b++) 565cd82a32eSJiri Olsa set_bit(b, bits); 566cd82a32eSJiri Olsa } 567dc098b35SAndi Kleen 568dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 569dc098b35SAndi Kleen struct perf_pmu_alias *alias) 570dc098b35SAndi Kleen { 571dc098b35SAndi Kleen snprintf(buf, len, "%s/%s/", pmu->name, alias->name); 572dc098b35SAndi Kleen return buf; 573dc098b35SAndi Kleen } 574dc098b35SAndi Kleen 575dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 576dc098b35SAndi Kleen struct perf_pmu_alias *alias) 577dc098b35SAndi Kleen { 578dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 579dc098b35SAndi Kleen return buf; 580dc098b35SAndi Kleen } 581dc098b35SAndi Kleen 582dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b) 583dc098b35SAndi Kleen { 584dc098b35SAndi Kleen const char * const *as = a; 585dc098b35SAndi Kleen const char * const *bs = b; 586dc098b35SAndi Kleen return strcmp(*as, *bs); 587dc098b35SAndi Kleen } 588dc098b35SAndi Kleen 589dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only) 590dc098b35SAndi Kleen { 591dc098b35SAndi Kleen struct perf_pmu *pmu; 592dc098b35SAndi Kleen struct perf_pmu_alias *alias; 593dc098b35SAndi Kleen char buf[1024]; 594dc098b35SAndi Kleen int printed = 0; 595dc098b35SAndi Kleen int len, j; 596dc098b35SAndi Kleen char **aliases; 597dc098b35SAndi Kleen 598dc098b35SAndi Kleen pmu = NULL; 599dc098b35SAndi Kleen len = 0; 600dc098b35SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) 601dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 602dc098b35SAndi Kleen len++; 603dc098b35SAndi Kleen aliases = malloc(sizeof(char *) * len); 604dc098b35SAndi Kleen if (!aliases) 605dc098b35SAndi Kleen return; 606dc098b35SAndi Kleen pmu = NULL; 607dc098b35SAndi Kleen j = 0; 608dc098b35SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) 609dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 610dc098b35SAndi Kleen char *name = format_alias(buf, sizeof(buf), pmu, alias); 611dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 612dc098b35SAndi Kleen 613dc098b35SAndi Kleen if (event_glob != NULL && 614dc098b35SAndi Kleen !(strglobmatch(name, event_glob) || 615dc098b35SAndi Kleen (!is_cpu && strglobmatch(alias->name, 616dc098b35SAndi Kleen event_glob)))) 617dc098b35SAndi Kleen continue; 618dc098b35SAndi Kleen aliases[j] = name; 619dc098b35SAndi Kleen if (is_cpu && !name_only) 620dc098b35SAndi Kleen aliases[j] = format_alias_or(buf, sizeof(buf), 621dc098b35SAndi Kleen pmu, alias); 622dc098b35SAndi Kleen aliases[j] = strdup(aliases[j]); 623dc098b35SAndi Kleen j++; 624dc098b35SAndi Kleen } 625dc098b35SAndi Kleen len = j; 626dc098b35SAndi Kleen qsort(aliases, len, sizeof(char *), cmp_string); 627dc098b35SAndi Kleen for (j = 0; j < len; j++) { 628dc098b35SAndi Kleen if (name_only) { 629dc098b35SAndi Kleen printf("%s ", aliases[j]); 630dc098b35SAndi Kleen continue; 631dc098b35SAndi Kleen } 632dc098b35SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j]); 633dc098b35SAndi Kleen free(aliases[j]); 634dc098b35SAndi Kleen printed++; 635dc098b35SAndi Kleen } 636dc098b35SAndi Kleen if (printed) 637dc098b35SAndi Kleen printf("\n"); 638dc098b35SAndi Kleen free(aliases); 639dc098b35SAndi Kleen } 640