1cd82a32eSJiri Olsa #include <linux/list.h> 2cd82a32eSJiri Olsa #include <sys/types.h> 3cd82a32eSJiri Olsa #include <unistd.h> 4cd82a32eSJiri Olsa #include <stdio.h> 5cd82a32eSJiri Olsa #include <dirent.h> 64299a549SJiri Olsa #include "fs.h" 7410136f5SStephane Eranian #include <locale.h> 8cd82a32eSJiri Olsa #include "util.h" 9cd82a32eSJiri Olsa #include "pmu.h" 10cd82a32eSJiri Olsa #include "parse-events.h" 117ae92e74SYan, Zheng #include "cpumap.h" 12cd82a32eSJiri Olsa 13410136f5SStephane Eranian #define UNIT_MAX_LEN 31 /* max length for event unit name */ 14410136f5SStephane Eranian 15ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_alias { 16ab1bf653SArnaldo Carvalho de Melo char *name; 17ab1bf653SArnaldo Carvalho de Melo struct list_head terms; 18ab1bf653SArnaldo Carvalho de Melo struct list_head list; 19410136f5SStephane Eranian char unit[UNIT_MAX_LEN+1]; 20410136f5SStephane Eranian double scale; 21ab1bf653SArnaldo Carvalho de Melo }; 22ab1bf653SArnaldo Carvalho de Melo 23ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 24ab1bf653SArnaldo Carvalho de Melo char *name; 25ab1bf653SArnaldo Carvalho de Melo int value; 26ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 27ab1bf653SArnaldo Carvalho de Melo struct list_head list; 28ab1bf653SArnaldo Carvalho de Melo }; 29ab1bf653SArnaldo Carvalho de Melo 3050a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 3150a9667cSRobert Richter 32cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 33cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 34cd82a32eSJiri Olsa 35cd82a32eSJiri Olsa static LIST_HEAD(pmus); 36cd82a32eSJiri Olsa 37cd82a32eSJiri Olsa /* 38cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 39cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 40cd82a32eSJiri Olsa */ 41cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 42cd82a32eSJiri Olsa { 43cd82a32eSJiri Olsa struct dirent *evt_ent; 44cd82a32eSJiri Olsa DIR *format_dir; 45cd82a32eSJiri Olsa int ret = 0; 46cd82a32eSJiri Olsa 47cd82a32eSJiri Olsa format_dir = opendir(dir); 48cd82a32eSJiri Olsa if (!format_dir) 49cd82a32eSJiri Olsa return -EINVAL; 50cd82a32eSJiri Olsa 51cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 52cd82a32eSJiri Olsa char path[PATH_MAX]; 53cd82a32eSJiri Olsa char *name = evt_ent->d_name; 54cd82a32eSJiri Olsa FILE *file; 55cd82a32eSJiri Olsa 56cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 57cd82a32eSJiri Olsa continue; 58cd82a32eSJiri Olsa 59cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 60cd82a32eSJiri Olsa 61cd82a32eSJiri Olsa ret = -EINVAL; 62cd82a32eSJiri Olsa file = fopen(path, "r"); 63cd82a32eSJiri Olsa if (!file) 64cd82a32eSJiri Olsa break; 65cd82a32eSJiri Olsa 66cd82a32eSJiri Olsa perf_pmu_in = file; 67cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 68cd82a32eSJiri Olsa fclose(file); 69cd82a32eSJiri Olsa } 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa closedir(format_dir); 72cd82a32eSJiri Olsa return ret; 73cd82a32eSJiri Olsa } 74cd82a32eSJiri Olsa 75cd82a32eSJiri Olsa /* 76cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 77cd82a32eSJiri Olsa * located at: 78cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 79cd82a32eSJiri Olsa */ 80b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 81cd82a32eSJiri Olsa { 82cd82a32eSJiri Olsa struct stat st; 83cd82a32eSJiri Olsa char path[PATH_MAX]; 84cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 85cd82a32eSJiri Olsa 86cd82a32eSJiri Olsa if (!sysfs) 87cd82a32eSJiri Olsa return -1; 88cd82a32eSJiri Olsa 89cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 9050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 91cd82a32eSJiri Olsa 92cd82a32eSJiri Olsa if (stat(path, &st) < 0) 939bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 94cd82a32eSJiri Olsa 95cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 96cd82a32eSJiri Olsa return -1; 97cd82a32eSJiri Olsa 98cd82a32eSJiri Olsa return 0; 99cd82a32eSJiri Olsa } 100cd82a32eSJiri Olsa 101410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 102410136f5SStephane Eranian { 103410136f5SStephane Eranian struct stat st; 104410136f5SStephane Eranian ssize_t sret; 105410136f5SStephane Eranian char scale[128]; 106410136f5SStephane Eranian int fd, ret = -1; 107410136f5SStephane Eranian char path[PATH_MAX]; 108410136f5SStephane Eranian char *lc; 109410136f5SStephane Eranian 110410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 111410136f5SStephane Eranian 112410136f5SStephane Eranian fd = open(path, O_RDONLY); 113410136f5SStephane Eranian if (fd == -1) 114410136f5SStephane Eranian return -1; 115410136f5SStephane Eranian 116410136f5SStephane Eranian if (fstat(fd, &st) < 0) 117410136f5SStephane Eranian goto error; 118410136f5SStephane Eranian 119410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 120410136f5SStephane Eranian if (sret < 0) 121410136f5SStephane Eranian goto error; 122410136f5SStephane Eranian 123410136f5SStephane Eranian scale[sret] = '\0'; 124410136f5SStephane Eranian /* 125410136f5SStephane Eranian * save current locale 126410136f5SStephane Eranian */ 127410136f5SStephane Eranian lc = setlocale(LC_NUMERIC, NULL); 128410136f5SStephane Eranian 129410136f5SStephane Eranian /* 130410136f5SStephane Eranian * force to C locale to ensure kernel 131410136f5SStephane Eranian * scale string is converted correctly. 132410136f5SStephane Eranian * kernel uses default C locale. 133410136f5SStephane Eranian */ 134410136f5SStephane Eranian setlocale(LC_NUMERIC, "C"); 135410136f5SStephane Eranian 136410136f5SStephane Eranian alias->scale = strtod(scale, NULL); 137410136f5SStephane Eranian 138410136f5SStephane Eranian /* restore locale */ 139410136f5SStephane Eranian setlocale(LC_NUMERIC, lc); 140410136f5SStephane Eranian 141410136f5SStephane Eranian ret = 0; 142410136f5SStephane Eranian error: 143410136f5SStephane Eranian close(fd); 144410136f5SStephane Eranian return ret; 145410136f5SStephane Eranian } 146410136f5SStephane Eranian 147410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 148410136f5SStephane Eranian { 149410136f5SStephane Eranian char path[PATH_MAX]; 150410136f5SStephane Eranian ssize_t sret; 151410136f5SStephane Eranian int fd; 152410136f5SStephane Eranian 153410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 154410136f5SStephane Eranian 155410136f5SStephane Eranian fd = open(path, O_RDONLY); 156410136f5SStephane Eranian if (fd == -1) 157410136f5SStephane Eranian return -1; 158410136f5SStephane Eranian 159410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 160410136f5SStephane Eranian if (sret < 0) 161410136f5SStephane Eranian goto error; 162410136f5SStephane Eranian 163410136f5SStephane Eranian close(fd); 164410136f5SStephane Eranian 165410136f5SStephane Eranian alias->unit[sret] = '\0'; 166410136f5SStephane Eranian 167410136f5SStephane Eranian return 0; 168410136f5SStephane Eranian error: 169410136f5SStephane Eranian close(fd); 170410136f5SStephane Eranian alias->unit[0] = '\0'; 171410136f5SStephane Eranian return -1; 172410136f5SStephane Eranian } 173410136f5SStephane Eranian 174410136f5SStephane Eranian static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 175a6146d50SZheng Yan { 1765c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 177a6146d50SZheng Yan char buf[256]; 178a6146d50SZheng Yan int ret; 179a6146d50SZheng Yan 180a6146d50SZheng Yan ret = fread(buf, 1, sizeof(buf), file); 181a6146d50SZheng Yan if (ret == 0) 182a6146d50SZheng Yan return -EINVAL; 183a6146d50SZheng Yan buf[ret] = 0; 184a6146d50SZheng Yan 185a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 186a6146d50SZheng Yan if (!alias) 187a6146d50SZheng Yan return -ENOMEM; 188a6146d50SZheng Yan 189a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 190410136f5SStephane Eranian alias->scale = 1.0; 191410136f5SStephane Eranian alias->unit[0] = '\0'; 192410136f5SStephane Eranian 193a6146d50SZheng Yan ret = parse_events_terms(&alias->terms, buf); 194a6146d50SZheng Yan if (ret) { 195a6146d50SZheng Yan free(alias); 196a6146d50SZheng Yan return ret; 197a6146d50SZheng Yan } 198a6146d50SZheng Yan 199a6146d50SZheng Yan alias->name = strdup(name); 200410136f5SStephane Eranian /* 201410136f5SStephane Eranian * load unit name and scale if available 202410136f5SStephane Eranian */ 203410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 204410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 205410136f5SStephane Eranian 206a6146d50SZheng Yan list_add_tail(&alias->list, list); 207410136f5SStephane Eranian 208a6146d50SZheng Yan return 0; 209a6146d50SZheng Yan } 210a6146d50SZheng Yan 211a6146d50SZheng Yan /* 212a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 213a6146d50SZheng Yan * specified in 'dir' parameter. 214a6146d50SZheng Yan */ 215a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 216a6146d50SZheng Yan { 217a6146d50SZheng Yan struct dirent *evt_ent; 218a6146d50SZheng Yan DIR *event_dir; 219410136f5SStephane Eranian size_t len; 220a6146d50SZheng Yan int ret = 0; 221a6146d50SZheng Yan 222a6146d50SZheng Yan event_dir = opendir(dir); 223a6146d50SZheng Yan if (!event_dir) 224a6146d50SZheng Yan return -EINVAL; 225a6146d50SZheng Yan 226a6146d50SZheng Yan while (!ret && (evt_ent = readdir(event_dir))) { 227a6146d50SZheng Yan char path[PATH_MAX]; 228a6146d50SZheng Yan char *name = evt_ent->d_name; 229a6146d50SZheng Yan FILE *file; 230a6146d50SZheng Yan 231a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 232a6146d50SZheng Yan continue; 233a6146d50SZheng Yan 234410136f5SStephane Eranian /* 235410136f5SStephane Eranian * skip .unit and .scale info files 236410136f5SStephane Eranian * parsed in perf_pmu__new_alias() 237410136f5SStephane Eranian */ 238410136f5SStephane Eranian len = strlen(name); 239410136f5SStephane Eranian if (len > 5 && !strcmp(name + len - 5, ".unit")) 240410136f5SStephane Eranian continue; 241410136f5SStephane Eranian if (len > 6 && !strcmp(name + len - 6, ".scale")) 242410136f5SStephane Eranian continue; 243410136f5SStephane Eranian 244a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 245a6146d50SZheng Yan 246a6146d50SZheng Yan ret = -EINVAL; 247a6146d50SZheng Yan file = fopen(path, "r"); 248a6146d50SZheng Yan if (!file) 249a6146d50SZheng Yan break; 250410136f5SStephane Eranian 251410136f5SStephane Eranian ret = perf_pmu__new_alias(head, dir, name, file); 252a6146d50SZheng Yan fclose(file); 253a6146d50SZheng Yan } 254a6146d50SZheng Yan 255a6146d50SZheng Yan closedir(event_dir); 256a6146d50SZheng Yan return ret; 257a6146d50SZheng Yan } 258a6146d50SZheng Yan 259a6146d50SZheng Yan /* 260a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 261a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 262a6146d50SZheng Yan */ 263b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 264a6146d50SZheng Yan { 265a6146d50SZheng Yan struct stat st; 266a6146d50SZheng Yan char path[PATH_MAX]; 267cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 268a6146d50SZheng Yan 269a6146d50SZheng Yan if (!sysfs) 270a6146d50SZheng Yan return -1; 271a6146d50SZheng Yan 272a6146d50SZheng Yan snprintf(path, PATH_MAX, 273a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 274a6146d50SZheng Yan 275a6146d50SZheng Yan if (stat(path, &st) < 0) 2763fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 277a6146d50SZheng Yan 278a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 279a6146d50SZheng Yan return -1; 280a6146d50SZheng Yan 281a6146d50SZheng Yan return 0; 282a6146d50SZheng Yan } 283a6146d50SZheng Yan 2845c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 285a6146d50SZheng Yan struct list_head *terms) 286a6146d50SZheng Yan { 2876cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *clone; 288a6146d50SZheng Yan LIST_HEAD(list); 289a6146d50SZheng Yan int ret; 290a6146d50SZheng Yan 291a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 2926cee6cd3SArnaldo Carvalho de Melo ret = parse_events_term__clone(&clone, term); 293a6146d50SZheng Yan if (ret) { 294a6146d50SZheng Yan parse_events__free_terms(&list); 295a6146d50SZheng Yan return ret; 296a6146d50SZheng Yan } 297a6146d50SZheng Yan list_add_tail(&clone->list, &list); 298a6146d50SZheng Yan } 299a6146d50SZheng Yan list_splice(&list, terms); 300a6146d50SZheng Yan return 0; 301a6146d50SZheng Yan } 302a6146d50SZheng Yan 303cd82a32eSJiri Olsa /* 304cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 305cd82a32eSJiri Olsa * located at: 306cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 307cd82a32eSJiri Olsa */ 308b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 309cd82a32eSJiri Olsa { 310cd82a32eSJiri Olsa struct stat st; 311cd82a32eSJiri Olsa char path[PATH_MAX]; 312cd82a32eSJiri Olsa FILE *file; 313cd82a32eSJiri Olsa int ret = 0; 314cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 315cd82a32eSJiri Olsa 316cd82a32eSJiri Olsa if (!sysfs) 317cd82a32eSJiri Olsa return -1; 318cd82a32eSJiri Olsa 319cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 32050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 321cd82a32eSJiri Olsa 322cd82a32eSJiri Olsa if (stat(path, &st) < 0) 323cd82a32eSJiri Olsa return -1; 324cd82a32eSJiri Olsa 325cd82a32eSJiri Olsa file = fopen(path, "r"); 326cd82a32eSJiri Olsa if (!file) 327cd82a32eSJiri Olsa return -EINVAL; 328cd82a32eSJiri Olsa 329cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 330cd82a32eSJiri Olsa ret = -1; 331cd82a32eSJiri Olsa 332cd82a32eSJiri Olsa fclose(file); 333cd82a32eSJiri Olsa return ret; 334cd82a32eSJiri Olsa } 335cd82a32eSJiri Olsa 33650a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 33750a9667cSRobert Richter static void pmu_read_sysfs(void) 33850a9667cSRobert Richter { 33950a9667cSRobert Richter char path[PATH_MAX]; 34050a9667cSRobert Richter DIR *dir; 34150a9667cSRobert Richter struct dirent *dent; 342cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 34350a9667cSRobert Richter 34450a9667cSRobert Richter if (!sysfs) 34550a9667cSRobert Richter return; 34650a9667cSRobert Richter 34750a9667cSRobert Richter snprintf(path, PATH_MAX, 34850a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 34950a9667cSRobert Richter 35050a9667cSRobert Richter dir = opendir(path); 35150a9667cSRobert Richter if (!dir) 35250a9667cSRobert Richter return; 35350a9667cSRobert Richter 35450a9667cSRobert Richter while ((dent = readdir(dir))) { 35550a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 35650a9667cSRobert Richter continue; 35750a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 35850a9667cSRobert Richter perf_pmu__find(dent->d_name); 35950a9667cSRobert Richter } 36050a9667cSRobert Richter 36150a9667cSRobert Richter closedir(dir); 36250a9667cSRobert Richter } 36350a9667cSRobert Richter 364b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 3657ae92e74SYan, Zheng { 3667ae92e74SYan, Zheng struct stat st; 3677ae92e74SYan, Zheng char path[PATH_MAX]; 3687ae92e74SYan, Zheng FILE *file; 3697ae92e74SYan, Zheng struct cpu_map *cpus; 370cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 3717ae92e74SYan, Zheng 3727ae92e74SYan, Zheng if (!sysfs) 3737ae92e74SYan, Zheng return NULL; 3747ae92e74SYan, Zheng 3757ae92e74SYan, Zheng snprintf(path, PATH_MAX, 3767ae92e74SYan, Zheng "%s/bus/event_source/devices/%s/cpumask", sysfs, name); 3777ae92e74SYan, Zheng 3787ae92e74SYan, Zheng if (stat(path, &st) < 0) 3797ae92e74SYan, Zheng return NULL; 3807ae92e74SYan, Zheng 3817ae92e74SYan, Zheng file = fopen(path, "r"); 3827ae92e74SYan, Zheng if (!file) 3837ae92e74SYan, Zheng return NULL; 3847ae92e74SYan, Zheng 3857ae92e74SYan, Zheng cpus = cpu_map__read(file); 3867ae92e74SYan, Zheng fclose(file); 3877ae92e74SYan, Zheng return cpus; 3887ae92e74SYan, Zheng } 3897ae92e74SYan, Zheng 390b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 391cd82a32eSJiri Olsa { 392cd82a32eSJiri Olsa struct perf_pmu *pmu; 393cd82a32eSJiri Olsa LIST_HEAD(format); 394a6146d50SZheng Yan LIST_HEAD(aliases); 395cd82a32eSJiri Olsa __u32 type; 396cd82a32eSJiri Olsa 397cd82a32eSJiri Olsa /* 398cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 399cd82a32eSJiri Olsa * type value and format definitions. Load both right 400cd82a32eSJiri Olsa * now. 401cd82a32eSJiri Olsa */ 402cd82a32eSJiri Olsa if (pmu_format(name, &format)) 403cd82a32eSJiri Olsa return NULL; 404cd82a32eSJiri Olsa 4053fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 4063fded963SJiri Olsa return NULL; 4073fded963SJiri Olsa 408cd82a32eSJiri Olsa if (pmu_type(name, &type)) 409cd82a32eSJiri Olsa return NULL; 410cd82a32eSJiri Olsa 411cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 412cd82a32eSJiri Olsa if (!pmu) 413cd82a32eSJiri Olsa return NULL; 414cd82a32eSJiri Olsa 4157ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 4167ae92e74SYan, Zheng 417cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 418a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 419cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 420a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 421cd82a32eSJiri Olsa pmu->name = strdup(name); 422cd82a32eSJiri Olsa pmu->type = type; 4239bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 424cd82a32eSJiri Olsa return pmu; 425cd82a32eSJiri Olsa } 426cd82a32eSJiri Olsa 427b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 428cd82a32eSJiri Olsa { 429cd82a32eSJiri Olsa struct perf_pmu *pmu; 430cd82a32eSJiri Olsa 431cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 432cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 433cd82a32eSJiri Olsa return pmu; 434cd82a32eSJiri Olsa 435cd82a32eSJiri Olsa return NULL; 436cd82a32eSJiri Olsa } 437cd82a32eSJiri Olsa 43850a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 43950a9667cSRobert Richter { 44050a9667cSRobert Richter /* 44150a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 44250a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 44350a9667cSRobert Richter */ 44450a9667cSRobert Richter if (!pmu) { 44550a9667cSRobert Richter pmu_read_sysfs(); 44650a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 44750a9667cSRobert Richter } 44850a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 44950a9667cSRobert Richter return pmu; 45050a9667cSRobert Richter return NULL; 45150a9667cSRobert Richter } 45250a9667cSRobert Richter 453b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 454cd82a32eSJiri Olsa { 455cd82a32eSJiri Olsa struct perf_pmu *pmu; 456cd82a32eSJiri Olsa 457cd82a32eSJiri Olsa /* 458cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 459cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 460cd82a32eSJiri Olsa * the pmu format definitions. 461cd82a32eSJiri Olsa */ 462cd82a32eSJiri Olsa pmu = pmu_find(name); 463cd82a32eSJiri Olsa if (pmu) 464cd82a32eSJiri Olsa return pmu; 465cd82a32eSJiri Olsa 466cd82a32eSJiri Olsa return pmu_lookup(name); 467cd82a32eSJiri Olsa } 468cd82a32eSJiri Olsa 4695c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 470cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name) 471cd82a32eSJiri Olsa { 4725c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 473cd82a32eSJiri Olsa 474cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 475cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 476cd82a32eSJiri Olsa return format; 477cd82a32eSJiri Olsa 478cd82a32eSJiri Olsa return NULL; 479cd82a32eSJiri Olsa } 480cd82a32eSJiri Olsa 481cd82a32eSJiri Olsa /* 482cd82a32eSJiri Olsa * Returns value based on the format definition (format parameter) 483cd82a32eSJiri Olsa * and unformated value (value parameter). 484cd82a32eSJiri Olsa * 485cd82a32eSJiri Olsa * TODO maybe optimize a little ;) 486cd82a32eSJiri Olsa */ 487cd82a32eSJiri Olsa static __u64 pmu_format_value(unsigned long *format, __u64 value) 488cd82a32eSJiri Olsa { 489cd82a32eSJiri Olsa unsigned long fbit, vbit; 490cd82a32eSJiri Olsa __u64 v = 0; 491cd82a32eSJiri Olsa 492cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 493cd82a32eSJiri Olsa 494cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 495cd82a32eSJiri Olsa continue; 496cd82a32eSJiri Olsa 497cd82a32eSJiri Olsa if (!(value & (1llu << vbit++))) 498cd82a32eSJiri Olsa continue; 499cd82a32eSJiri Olsa 500cd82a32eSJiri Olsa v |= (1llu << fbit); 501cd82a32eSJiri Olsa } 502cd82a32eSJiri Olsa 503cd82a32eSJiri Olsa return v; 504cd82a32eSJiri Olsa } 505cd82a32eSJiri Olsa 506cd82a32eSJiri Olsa /* 507cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 50888aca8d9SCody P Schafer * user input data - term parameter. 509cd82a32eSJiri Olsa */ 510cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 511cd82a32eSJiri Olsa struct perf_event_attr *attr, 5126cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 513cd82a32eSJiri Olsa { 5145c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 515cd82a32eSJiri Olsa __u64 *vp; 516cd82a32eSJiri Olsa 517cd82a32eSJiri Olsa /* 518cd82a32eSJiri Olsa * Support only for hardcoded and numnerial terms. 519cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 520cd82a32eSJiri Olsa * to be done for them. 521cd82a32eSJiri Olsa */ 522cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 523cd82a32eSJiri Olsa return 0; 524cd82a32eSJiri Olsa 52516fa7e82SJiri Olsa if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) 526cd82a32eSJiri Olsa return -EINVAL; 527cd82a32eSJiri Olsa 528cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 529cd82a32eSJiri Olsa if (!format) 530cd82a32eSJiri Olsa return -EINVAL; 531cd82a32eSJiri Olsa 532cd82a32eSJiri Olsa switch (format->value) { 533cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 534cd82a32eSJiri Olsa vp = &attr->config; 535cd82a32eSJiri Olsa break; 536cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 537cd82a32eSJiri Olsa vp = &attr->config1; 538cd82a32eSJiri Olsa break; 539cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 540cd82a32eSJiri Olsa vp = &attr->config2; 541cd82a32eSJiri Olsa break; 542cd82a32eSJiri Olsa default: 543cd82a32eSJiri Olsa return -EINVAL; 544cd82a32eSJiri Olsa } 545cd82a32eSJiri Olsa 54616fa7e82SJiri Olsa /* 54716fa7e82SJiri Olsa * XXX If we ever decide to go with string values for 54816fa7e82SJiri Olsa * non-hardcoded terms, here's the place to translate 54916fa7e82SJiri Olsa * them into value. 55016fa7e82SJiri Olsa */ 551cd82a32eSJiri Olsa *vp |= pmu_format_value(format->bits, term->val.num); 552cd82a32eSJiri Olsa return 0; 553cd82a32eSJiri Olsa } 554cd82a32eSJiri Olsa 555cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 556cff7f956SJiri Olsa struct perf_event_attr *attr, 557cd82a32eSJiri Olsa struct list_head *head_terms) 558cd82a32eSJiri Olsa { 5596cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 560cd82a32eSJiri Olsa 5616b5fc39bSJiri Olsa list_for_each_entry(term, head_terms, list) 562cd82a32eSJiri Olsa if (pmu_config_term(formats, attr, term)) 563cd82a32eSJiri Olsa return -EINVAL; 564cd82a32eSJiri Olsa 565cd82a32eSJiri Olsa return 0; 566cd82a32eSJiri Olsa } 567cd82a32eSJiri Olsa 568cd82a32eSJiri Olsa /* 569cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 570cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 571cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 572cd82a32eSJiri Olsa */ 573cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 574cd82a32eSJiri Olsa struct list_head *head_terms) 575cd82a32eSJiri Olsa { 576cd82a32eSJiri Olsa attr->type = pmu->type; 577cff7f956SJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms); 578cd82a32eSJiri Olsa } 579cd82a32eSJiri Olsa 5805c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 5816cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 582a6146d50SZheng Yan { 5835c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 584a6146d50SZheng Yan char *name; 585a6146d50SZheng Yan 586a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 587a6146d50SZheng Yan return NULL; 588a6146d50SZheng Yan 589a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 590a6146d50SZheng Yan if (term->val.num != 1) 591a6146d50SZheng Yan return NULL; 592a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 593a6146d50SZheng Yan return NULL; 594a6146d50SZheng Yan name = term->config; 595a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 596a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 597a6146d50SZheng Yan return NULL; 598a6146d50SZheng Yan name = term->val.str; 599a6146d50SZheng Yan } else { 600a6146d50SZheng Yan return NULL; 601a6146d50SZheng Yan } 602a6146d50SZheng Yan 603a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 604a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 605a6146d50SZheng Yan return alias; 606a6146d50SZheng Yan } 607a6146d50SZheng Yan return NULL; 608a6146d50SZheng Yan } 609a6146d50SZheng Yan 610410136f5SStephane Eranian 611410136f5SStephane Eranian static int check_unit_scale(struct perf_pmu_alias *alias, 612410136f5SStephane Eranian char **unit, double *scale) 613410136f5SStephane Eranian { 614410136f5SStephane Eranian /* 615410136f5SStephane Eranian * Only one term in event definition can 616410136f5SStephane Eranian * define unit and scale, fail if there's 617410136f5SStephane Eranian * more than one. 618410136f5SStephane Eranian */ 619410136f5SStephane Eranian if ((*unit && alias->unit) || 620410136f5SStephane Eranian (*scale && alias->scale)) 621410136f5SStephane Eranian return -EINVAL; 622410136f5SStephane Eranian 623410136f5SStephane Eranian if (alias->unit) 624410136f5SStephane Eranian *unit = alias->unit; 625410136f5SStephane Eranian 626410136f5SStephane Eranian if (alias->scale) 627410136f5SStephane Eranian *scale = alias->scale; 628410136f5SStephane Eranian 629410136f5SStephane Eranian return 0; 630410136f5SStephane Eranian } 631410136f5SStephane Eranian 632a6146d50SZheng Yan /* 633a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 634a6146d50SZheng Yan * defined for the alias 635a6146d50SZheng Yan */ 636410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 637410136f5SStephane Eranian char **unit, double *scale) 638a6146d50SZheng Yan { 6396cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 6405c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 641a6146d50SZheng Yan int ret; 642a6146d50SZheng Yan 643410136f5SStephane Eranian *unit = NULL; 644410136f5SStephane Eranian *scale = 0; 645410136f5SStephane Eranian 646a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 647a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 648a6146d50SZheng Yan if (!alias) 649a6146d50SZheng Yan continue; 650a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 651a6146d50SZheng Yan if (ret) 652a6146d50SZheng Yan return ret; 653410136f5SStephane Eranian 654410136f5SStephane Eranian ret = check_unit_scale(alias, unit, scale); 655410136f5SStephane Eranian if (ret) 656410136f5SStephane Eranian return ret; 657410136f5SStephane Eranian 658a6146d50SZheng Yan list_del(&term->list); 659a6146d50SZheng Yan free(term); 660a6146d50SZheng Yan } 661a6146d50SZheng Yan return 0; 662a6146d50SZheng Yan } 663a6146d50SZheng Yan 664cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 665cd82a32eSJiri Olsa int config, unsigned long *bits) 666cd82a32eSJiri Olsa { 6675c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 668cd82a32eSJiri Olsa 669cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 670cd82a32eSJiri Olsa if (!format) 671cd82a32eSJiri Olsa return -ENOMEM; 672cd82a32eSJiri Olsa 673cd82a32eSJiri Olsa format->name = strdup(name); 674cd82a32eSJiri Olsa format->value = config; 675cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 676cd82a32eSJiri Olsa 677cd82a32eSJiri Olsa list_add_tail(&format->list, list); 678cd82a32eSJiri Olsa return 0; 679cd82a32eSJiri Olsa } 680cd82a32eSJiri Olsa 681cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 682cd82a32eSJiri Olsa { 683cd82a32eSJiri Olsa long b; 684cd82a32eSJiri Olsa 685cd82a32eSJiri Olsa if (!to) 686cd82a32eSJiri Olsa to = from; 687cd82a32eSJiri Olsa 68815268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 689cd82a32eSJiri Olsa for (b = from; b <= to; b++) 690cd82a32eSJiri Olsa set_bit(b, bits); 691cd82a32eSJiri Olsa } 692dc098b35SAndi Kleen 693dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 694dc098b35SAndi Kleen struct perf_pmu_alias *alias) 695dc098b35SAndi Kleen { 696dc098b35SAndi Kleen snprintf(buf, len, "%s/%s/", pmu->name, alias->name); 697dc098b35SAndi Kleen return buf; 698dc098b35SAndi Kleen } 699dc098b35SAndi Kleen 700dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 701dc098b35SAndi Kleen struct perf_pmu_alias *alias) 702dc098b35SAndi Kleen { 703dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 704dc098b35SAndi Kleen return buf; 705dc098b35SAndi Kleen } 706dc098b35SAndi Kleen 707dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b) 708dc098b35SAndi Kleen { 709dc098b35SAndi Kleen const char * const *as = a; 710dc098b35SAndi Kleen const char * const *bs = b; 711dc098b35SAndi Kleen return strcmp(*as, *bs); 712dc098b35SAndi Kleen } 713dc098b35SAndi Kleen 714dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only) 715dc098b35SAndi Kleen { 716dc098b35SAndi Kleen struct perf_pmu *pmu; 717dc098b35SAndi Kleen struct perf_pmu_alias *alias; 718dc098b35SAndi Kleen char buf[1024]; 719dc098b35SAndi Kleen int printed = 0; 720dc098b35SAndi Kleen int len, j; 721dc098b35SAndi Kleen char **aliases; 722dc098b35SAndi Kleen 723dc098b35SAndi Kleen pmu = NULL; 724dc098b35SAndi Kleen len = 0; 725dc098b35SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) 726dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 727dc098b35SAndi Kleen len++; 728dc098b35SAndi Kleen aliases = malloc(sizeof(char *) * len); 729dc098b35SAndi Kleen if (!aliases) 730dc098b35SAndi Kleen return; 731dc098b35SAndi Kleen pmu = NULL; 732dc098b35SAndi Kleen j = 0; 733dc098b35SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) 734dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 735dc098b35SAndi Kleen char *name = format_alias(buf, sizeof(buf), pmu, alias); 736dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 737dc098b35SAndi Kleen 738dc098b35SAndi Kleen if (event_glob != NULL && 739dc098b35SAndi Kleen !(strglobmatch(name, event_glob) || 740dc098b35SAndi Kleen (!is_cpu && strglobmatch(alias->name, 741dc098b35SAndi Kleen event_glob)))) 742dc098b35SAndi Kleen continue; 743dc098b35SAndi Kleen aliases[j] = name; 744dc098b35SAndi Kleen if (is_cpu && !name_only) 745dc098b35SAndi Kleen aliases[j] = format_alias_or(buf, sizeof(buf), 746dc098b35SAndi Kleen pmu, alias); 747dc098b35SAndi Kleen aliases[j] = strdup(aliases[j]); 748dc098b35SAndi Kleen j++; 749dc098b35SAndi Kleen } 750dc098b35SAndi Kleen len = j; 751dc098b35SAndi Kleen qsort(aliases, len, sizeof(char *), cmp_string); 752dc098b35SAndi Kleen for (j = 0; j < len; j++) { 753dc098b35SAndi Kleen if (name_only) { 754dc098b35SAndi Kleen printf("%s ", aliases[j]); 755dc098b35SAndi Kleen continue; 756dc098b35SAndi Kleen } 757dc098b35SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j]); 75874cf249dSArnaldo Carvalho de Melo zfree(&aliases[j]); 759dc098b35SAndi Kleen printed++; 760dc098b35SAndi Kleen } 761dc098b35SAndi Kleen if (printed) 762dc098b35SAndi Kleen printf("\n"); 763dc098b35SAndi Kleen free(aliases); 764dc098b35SAndi Kleen } 7654cabc3d1SAndi Kleen 7664cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 7674cabc3d1SAndi Kleen { 7684cabc3d1SAndi Kleen struct perf_pmu *pmu; 7694cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 7704cabc3d1SAndi Kleen 7714cabc3d1SAndi Kleen pmu = NULL; 7724cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 7734cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 7744cabc3d1SAndi Kleen continue; 7754cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 7764cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 7774cabc3d1SAndi Kleen return true; 7784cabc3d1SAndi Kleen } 7794cabc3d1SAndi Kleen return false; 7804cabc3d1SAndi Kleen } 781