1cd82a32eSJiri Olsa #include <linux/list.h> 2c5de47f2SSukadev Bhattiprolu #include <linux/compiler.h> 3cd82a32eSJiri Olsa #include <sys/types.h> 4cd82a32eSJiri Olsa #include <unistd.h> 5cd82a32eSJiri Olsa #include <stdio.h> 6dc0a6202SAdrian Hunter #include <stdbool.h> 77d4bdab5SAdrian Hunter #include <stdarg.h> 8cd82a32eSJiri Olsa #include <dirent.h> 9cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 10410136f5SStephane Eranian #include <locale.h> 11cd82a32eSJiri Olsa #include "util.h" 12cd82a32eSJiri Olsa #include "pmu.h" 13cd82a32eSJiri Olsa #include "parse-events.h" 147ae92e74SYan, Zheng #include "cpumap.h" 15cd82a32eSJiri Olsa 16ab1bf653SArnaldo Carvalho de Melo struct perf_pmu_format { 17ab1bf653SArnaldo Carvalho de Melo char *name; 18ab1bf653SArnaldo Carvalho de Melo int value; 19ab1bf653SArnaldo Carvalho de Melo DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS); 20ab1bf653SArnaldo Carvalho de Melo struct list_head list; 21ab1bf653SArnaldo Carvalho de Melo }; 22ab1bf653SArnaldo Carvalho de Melo 2350a9667cSRobert Richter #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 2450a9667cSRobert Richter 25cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 26cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 27cd82a32eSJiri Olsa 28cd82a32eSJiri Olsa static LIST_HEAD(pmus); 29cd82a32eSJiri Olsa 30cd82a32eSJiri Olsa /* 31cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 32cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 33cd82a32eSJiri Olsa */ 34cff7f956SJiri Olsa int perf_pmu__format_parse(char *dir, struct list_head *head) 35cd82a32eSJiri Olsa { 36cd82a32eSJiri Olsa struct dirent *evt_ent; 37cd82a32eSJiri Olsa DIR *format_dir; 38cd82a32eSJiri Olsa int ret = 0; 39cd82a32eSJiri Olsa 40cd82a32eSJiri Olsa format_dir = opendir(dir); 41cd82a32eSJiri Olsa if (!format_dir) 42cd82a32eSJiri Olsa return -EINVAL; 43cd82a32eSJiri Olsa 44cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 45cd82a32eSJiri Olsa char path[PATH_MAX]; 46cd82a32eSJiri Olsa char *name = evt_ent->d_name; 47cd82a32eSJiri Olsa FILE *file; 48cd82a32eSJiri Olsa 49cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 50cd82a32eSJiri Olsa continue; 51cd82a32eSJiri Olsa 52cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 53cd82a32eSJiri Olsa 54cd82a32eSJiri Olsa ret = -EINVAL; 55cd82a32eSJiri Olsa file = fopen(path, "r"); 56cd82a32eSJiri Olsa if (!file) 57cd82a32eSJiri Olsa break; 58cd82a32eSJiri Olsa 59cd82a32eSJiri Olsa perf_pmu_in = file; 60cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 61cd82a32eSJiri Olsa fclose(file); 62cd82a32eSJiri Olsa } 63cd82a32eSJiri Olsa 64cd82a32eSJiri Olsa closedir(format_dir); 65cd82a32eSJiri Olsa return ret; 66cd82a32eSJiri Olsa } 67cd82a32eSJiri Olsa 68cd82a32eSJiri Olsa /* 69cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 70cd82a32eSJiri Olsa * located at: 71cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 72cd82a32eSJiri Olsa */ 73b6b96fb4SAdrian Hunter static int pmu_format(const char *name, struct list_head *format) 74cd82a32eSJiri Olsa { 75cd82a32eSJiri Olsa struct stat st; 76cd82a32eSJiri Olsa char path[PATH_MAX]; 77cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 78cd82a32eSJiri Olsa 79cd82a32eSJiri Olsa if (!sysfs) 80cd82a32eSJiri Olsa return -1; 81cd82a32eSJiri Olsa 82cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 8350a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name); 84cd82a32eSJiri Olsa 85cd82a32eSJiri Olsa if (stat(path, &st) < 0) 869bc8f9feSRobert Richter return 0; /* no error if format does not exist */ 87cd82a32eSJiri Olsa 88cff7f956SJiri Olsa if (perf_pmu__format_parse(path, format)) 89cd82a32eSJiri Olsa return -1; 90cd82a32eSJiri Olsa 91cd82a32eSJiri Olsa return 0; 92cd82a32eSJiri Olsa } 93cd82a32eSJiri Olsa 94410136f5SStephane Eranian static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) 95410136f5SStephane Eranian { 96410136f5SStephane Eranian struct stat st; 97410136f5SStephane Eranian ssize_t sret; 98410136f5SStephane Eranian char scale[128]; 99410136f5SStephane Eranian int fd, ret = -1; 100410136f5SStephane Eranian char path[PATH_MAX]; 1018a398897SStephane Eranian const char *lc; 102410136f5SStephane Eranian 103410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 104410136f5SStephane Eranian 105410136f5SStephane Eranian fd = open(path, O_RDONLY); 106410136f5SStephane Eranian if (fd == -1) 107410136f5SStephane Eranian return -1; 108410136f5SStephane Eranian 109410136f5SStephane Eranian if (fstat(fd, &st) < 0) 110410136f5SStephane Eranian goto error; 111410136f5SStephane Eranian 112410136f5SStephane Eranian sret = read(fd, scale, sizeof(scale)-1); 113410136f5SStephane Eranian if (sret < 0) 114410136f5SStephane Eranian goto error; 115410136f5SStephane Eranian 1169ecae065SMadhavan Srinivasan if (scale[sret - 1] == '\n') 1179ecae065SMadhavan Srinivasan scale[sret - 1] = '\0'; 1189ecae065SMadhavan Srinivasan else 119410136f5SStephane Eranian scale[sret] = '\0'; 1209ecae065SMadhavan Srinivasan 121410136f5SStephane Eranian /* 122410136f5SStephane Eranian * save current locale 123410136f5SStephane Eranian */ 124410136f5SStephane Eranian lc = setlocale(LC_NUMERIC, NULL); 125410136f5SStephane Eranian 126410136f5SStephane Eranian /* 127410136f5SStephane Eranian * force to C locale to ensure kernel 128410136f5SStephane Eranian * scale string is converted correctly. 129410136f5SStephane Eranian * kernel uses default C locale. 130410136f5SStephane Eranian */ 131410136f5SStephane Eranian setlocale(LC_NUMERIC, "C"); 132410136f5SStephane Eranian 133410136f5SStephane Eranian alias->scale = strtod(scale, NULL); 134410136f5SStephane Eranian 135410136f5SStephane Eranian /* restore locale */ 136410136f5SStephane Eranian setlocale(LC_NUMERIC, lc); 137410136f5SStephane Eranian 138410136f5SStephane Eranian ret = 0; 139410136f5SStephane Eranian error: 140410136f5SStephane Eranian close(fd); 141410136f5SStephane Eranian return ret; 142410136f5SStephane Eranian } 143410136f5SStephane Eranian 144410136f5SStephane Eranian static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) 145410136f5SStephane Eranian { 146410136f5SStephane Eranian char path[PATH_MAX]; 147410136f5SStephane Eranian ssize_t sret; 148410136f5SStephane Eranian int fd; 149410136f5SStephane Eranian 150410136f5SStephane Eranian snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); 151410136f5SStephane Eranian 152410136f5SStephane Eranian fd = open(path, O_RDONLY); 153410136f5SStephane Eranian if (fd == -1) 154410136f5SStephane Eranian return -1; 155410136f5SStephane Eranian 156410136f5SStephane Eranian sret = read(fd, alias->unit, UNIT_MAX_LEN); 157410136f5SStephane Eranian if (sret < 0) 158410136f5SStephane Eranian goto error; 159410136f5SStephane Eranian 160410136f5SStephane Eranian close(fd); 161410136f5SStephane Eranian 1629ecae065SMadhavan Srinivasan if (alias->unit[sret - 1] == '\n') 1639ecae065SMadhavan Srinivasan alias->unit[sret - 1] = '\0'; 1649ecae065SMadhavan Srinivasan else 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 174044330c1SMatt Fleming static int 175044330c1SMatt Fleming perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name) 176044330c1SMatt Fleming { 177044330c1SMatt Fleming char path[PATH_MAX]; 178044330c1SMatt Fleming int fd; 179044330c1SMatt Fleming 180044330c1SMatt Fleming snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name); 181044330c1SMatt Fleming 182044330c1SMatt Fleming fd = open(path, O_RDONLY); 183044330c1SMatt Fleming if (fd == -1) 184044330c1SMatt Fleming return -1; 185044330c1SMatt Fleming 186044330c1SMatt Fleming close(fd); 187044330c1SMatt Fleming 188044330c1SMatt Fleming alias->per_pkg = true; 189044330c1SMatt Fleming return 0; 190044330c1SMatt Fleming } 191044330c1SMatt Fleming 1921d9e446bSJiri Olsa static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, 1931d9e446bSJiri Olsa char *dir, char *name) 1941d9e446bSJiri Olsa { 1951d9e446bSJiri Olsa char path[PATH_MAX]; 1961d9e446bSJiri Olsa int fd; 1971d9e446bSJiri Olsa 1981d9e446bSJiri Olsa snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name); 1991d9e446bSJiri Olsa 2001d9e446bSJiri Olsa fd = open(path, O_RDONLY); 2011d9e446bSJiri Olsa if (fd == -1) 2021d9e446bSJiri Olsa return -1; 2031d9e446bSJiri Olsa 2041d9e446bSJiri Olsa alias->snapshot = true; 2051d9e446bSJiri Olsa close(fd); 2061d9e446bSJiri Olsa return 0; 2071d9e446bSJiri Olsa } 2081d9e446bSJiri Olsa 20970c646e0SSukadev Bhattiprolu static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 21070c646e0SSukadev Bhattiprolu char *desc __maybe_unused, char *val) 211a6146d50SZheng Yan { 2125c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 213a6146d50SZheng Yan int ret; 214a6146d50SZheng Yan 215a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 216a6146d50SZheng Yan if (!alias) 217a6146d50SZheng Yan return -ENOMEM; 218a6146d50SZheng Yan 219a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 220410136f5SStephane Eranian alias->scale = 1.0; 221410136f5SStephane Eranian alias->unit[0] = '\0'; 222044330c1SMatt Fleming alias->per_pkg = false; 223410136f5SStephane Eranian 22470c646e0SSukadev Bhattiprolu ret = parse_events_terms(&alias->terms, val); 225a6146d50SZheng Yan if (ret) { 22670c646e0SSukadev Bhattiprolu pr_err("Cannot parse alias %s: %d\n", val, ret); 227a6146d50SZheng Yan free(alias); 228a6146d50SZheng Yan return ret; 229a6146d50SZheng Yan } 230a6146d50SZheng Yan 231a6146d50SZheng Yan alias->name = strdup(name); 23270c646e0SSukadev Bhattiprolu if (dir) { 233410136f5SStephane Eranian /* 234410136f5SStephane Eranian * load unit name and scale if available 235410136f5SStephane Eranian */ 236410136f5SStephane Eranian perf_pmu__parse_unit(alias, dir, name); 237410136f5SStephane Eranian perf_pmu__parse_scale(alias, dir, name); 238044330c1SMatt Fleming perf_pmu__parse_per_pkg(alias, dir, name); 2391d9e446bSJiri Olsa perf_pmu__parse_snapshot(alias, dir, name); 24070c646e0SSukadev Bhattiprolu } 241410136f5SStephane Eranian 242a6146d50SZheng Yan list_add_tail(&alias->list, list); 243410136f5SStephane Eranian 244a6146d50SZheng Yan return 0; 245a6146d50SZheng Yan } 246a6146d50SZheng Yan 24770c646e0SSukadev Bhattiprolu static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 24870c646e0SSukadev Bhattiprolu { 24970c646e0SSukadev Bhattiprolu char buf[256]; 25070c646e0SSukadev Bhattiprolu int ret; 25170c646e0SSukadev Bhattiprolu 25270c646e0SSukadev Bhattiprolu ret = fread(buf, 1, sizeof(buf), file); 25370c646e0SSukadev Bhattiprolu if (ret == 0) 25470c646e0SSukadev Bhattiprolu return -EINVAL; 25570c646e0SSukadev Bhattiprolu 25670c646e0SSukadev Bhattiprolu buf[ret] = 0; 25770c646e0SSukadev Bhattiprolu 25870c646e0SSukadev Bhattiprolu return __perf_pmu__new_alias(list, dir, name, NULL, buf); 25970c646e0SSukadev Bhattiprolu } 26070c646e0SSukadev Bhattiprolu 26146441bdcSMatt Fleming static inline bool pmu_alias_info_file(char *name) 26246441bdcSMatt Fleming { 26346441bdcSMatt Fleming size_t len; 26446441bdcSMatt Fleming 26546441bdcSMatt Fleming len = strlen(name); 26646441bdcSMatt Fleming if (len > 5 && !strcmp(name + len - 5, ".unit")) 26746441bdcSMatt Fleming return true; 26846441bdcSMatt Fleming if (len > 6 && !strcmp(name + len - 6, ".scale")) 26946441bdcSMatt Fleming return true; 270044330c1SMatt Fleming if (len > 8 && !strcmp(name + len - 8, ".per-pkg")) 271044330c1SMatt Fleming return true; 2721d9e446bSJiri Olsa if (len > 9 && !strcmp(name + len - 9, ".snapshot")) 2731d9e446bSJiri Olsa return true; 27446441bdcSMatt Fleming 27546441bdcSMatt Fleming return false; 27646441bdcSMatt Fleming } 27746441bdcSMatt Fleming 278a6146d50SZheng Yan /* 279a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 280a6146d50SZheng Yan * specified in 'dir' parameter. 281a6146d50SZheng Yan */ 282a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 283a6146d50SZheng Yan { 284a6146d50SZheng Yan struct dirent *evt_ent; 285a6146d50SZheng Yan DIR *event_dir; 286a6146d50SZheng Yan int ret = 0; 287a6146d50SZheng Yan 288a6146d50SZheng Yan event_dir = opendir(dir); 289a6146d50SZheng Yan if (!event_dir) 290a6146d50SZheng Yan return -EINVAL; 291a6146d50SZheng Yan 292a6146d50SZheng Yan while (!ret && (evt_ent = readdir(event_dir))) { 293a6146d50SZheng Yan char path[PATH_MAX]; 294a6146d50SZheng Yan char *name = evt_ent->d_name; 295a6146d50SZheng Yan FILE *file; 296a6146d50SZheng Yan 297a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 298a6146d50SZheng Yan continue; 299a6146d50SZheng Yan 300410136f5SStephane Eranian /* 30146441bdcSMatt Fleming * skip info files parsed in perf_pmu__new_alias() 302410136f5SStephane Eranian */ 30346441bdcSMatt Fleming if (pmu_alias_info_file(name)) 304410136f5SStephane Eranian continue; 305410136f5SStephane Eranian 306a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 307a6146d50SZheng Yan 308a6146d50SZheng Yan ret = -EINVAL; 309a6146d50SZheng Yan file = fopen(path, "r"); 310a6146d50SZheng Yan if (!file) 311a6146d50SZheng Yan break; 312410136f5SStephane Eranian 313410136f5SStephane Eranian ret = perf_pmu__new_alias(head, dir, name, file); 314a6146d50SZheng Yan fclose(file); 315a6146d50SZheng Yan } 316a6146d50SZheng Yan 317a6146d50SZheng Yan closedir(event_dir); 318a6146d50SZheng Yan return ret; 319a6146d50SZheng Yan } 320a6146d50SZheng Yan 321a6146d50SZheng Yan /* 322a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 323a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 324a6146d50SZheng Yan */ 325b6b96fb4SAdrian Hunter static int pmu_aliases(const char *name, struct list_head *head) 326a6146d50SZheng Yan { 327a6146d50SZheng Yan struct stat st; 328a6146d50SZheng Yan char path[PATH_MAX]; 329cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 330a6146d50SZheng Yan 331a6146d50SZheng Yan if (!sysfs) 332a6146d50SZheng Yan return -1; 333a6146d50SZheng Yan 334a6146d50SZheng Yan snprintf(path, PATH_MAX, 335a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 336a6146d50SZheng Yan 337a6146d50SZheng Yan if (stat(path, &st) < 0) 3383fded963SJiri Olsa return 0; /* no error if 'events' does not exist */ 339a6146d50SZheng Yan 340a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 341a6146d50SZheng Yan return -1; 342a6146d50SZheng Yan 343a6146d50SZheng Yan return 0; 344a6146d50SZheng Yan } 345a6146d50SZheng Yan 3465c6ccc37SArnaldo Carvalho de Melo static int pmu_alias_terms(struct perf_pmu_alias *alias, 347a6146d50SZheng Yan struct list_head *terms) 348a6146d50SZheng Yan { 3497c2f8164SJiri Olsa struct parse_events_term *term, *cloned; 350a6146d50SZheng Yan LIST_HEAD(list); 351a6146d50SZheng Yan int ret; 352a6146d50SZheng Yan 353a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 3547c2f8164SJiri Olsa ret = parse_events_term__clone(&cloned, term); 355a6146d50SZheng Yan if (ret) { 356a6146d50SZheng Yan parse_events__free_terms(&list); 357a6146d50SZheng Yan return ret; 358a6146d50SZheng Yan } 3597c2f8164SJiri Olsa list_add_tail(&cloned->list, &list); 360a6146d50SZheng Yan } 361a6146d50SZheng Yan list_splice(&list, terms); 362a6146d50SZheng Yan return 0; 363a6146d50SZheng Yan } 364a6146d50SZheng Yan 365cd82a32eSJiri Olsa /* 366cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 367cd82a32eSJiri Olsa * located at: 368cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 369cd82a32eSJiri Olsa */ 370b6b96fb4SAdrian Hunter static int pmu_type(const char *name, __u32 *type) 371cd82a32eSJiri Olsa { 372cd82a32eSJiri Olsa struct stat st; 373cd82a32eSJiri Olsa char path[PATH_MAX]; 374cd82a32eSJiri Olsa FILE *file; 375cd82a32eSJiri Olsa int ret = 0; 376cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 377cd82a32eSJiri Olsa 378cd82a32eSJiri Olsa if (!sysfs) 379cd82a32eSJiri Olsa return -1; 380cd82a32eSJiri Olsa 381cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 38250a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name); 383cd82a32eSJiri Olsa 384cd82a32eSJiri Olsa if (stat(path, &st) < 0) 385cd82a32eSJiri Olsa return -1; 386cd82a32eSJiri Olsa 387cd82a32eSJiri Olsa file = fopen(path, "r"); 388cd82a32eSJiri Olsa if (!file) 389cd82a32eSJiri Olsa return -EINVAL; 390cd82a32eSJiri Olsa 391cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 392cd82a32eSJiri Olsa ret = -1; 393cd82a32eSJiri Olsa 394cd82a32eSJiri Olsa fclose(file); 395cd82a32eSJiri Olsa return ret; 396cd82a32eSJiri Olsa } 397cd82a32eSJiri Olsa 39850a9667cSRobert Richter /* Add all pmus in sysfs to pmu list: */ 39950a9667cSRobert Richter static void pmu_read_sysfs(void) 40050a9667cSRobert Richter { 40150a9667cSRobert Richter char path[PATH_MAX]; 40250a9667cSRobert Richter DIR *dir; 40350a9667cSRobert Richter struct dirent *dent; 404cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 40550a9667cSRobert Richter 40650a9667cSRobert Richter if (!sysfs) 40750a9667cSRobert Richter return; 40850a9667cSRobert Richter 40950a9667cSRobert Richter snprintf(path, PATH_MAX, 41050a9667cSRobert Richter "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); 41150a9667cSRobert Richter 41250a9667cSRobert Richter dir = opendir(path); 41350a9667cSRobert Richter if (!dir) 41450a9667cSRobert Richter return; 41550a9667cSRobert Richter 41650a9667cSRobert Richter while ((dent = readdir(dir))) { 41750a9667cSRobert Richter if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) 41850a9667cSRobert Richter continue; 41950a9667cSRobert Richter /* add to static LIST_HEAD(pmus): */ 42050a9667cSRobert Richter perf_pmu__find(dent->d_name); 42150a9667cSRobert Richter } 42250a9667cSRobert Richter 42350a9667cSRobert Richter closedir(dir); 42450a9667cSRobert Richter } 42550a9667cSRobert Richter 426b6b96fb4SAdrian Hunter static struct cpu_map *pmu_cpumask(const char *name) 4277ae92e74SYan, Zheng { 4287ae92e74SYan, Zheng struct stat st; 4297ae92e74SYan, Zheng char path[PATH_MAX]; 4307ae92e74SYan, Zheng FILE *file; 4317ae92e74SYan, Zheng struct cpu_map *cpus; 432cf38fadaSArnaldo Carvalho de Melo const char *sysfs = sysfs__mountpoint(); 4337ae92e74SYan, Zheng 4347ae92e74SYan, Zheng if (!sysfs) 4357ae92e74SYan, Zheng return NULL; 4367ae92e74SYan, Zheng 4377ae92e74SYan, Zheng snprintf(path, PATH_MAX, 4387ae92e74SYan, Zheng "%s/bus/event_source/devices/%s/cpumask", sysfs, name); 4397ae92e74SYan, Zheng 4407ae92e74SYan, Zheng if (stat(path, &st) < 0) 4417ae92e74SYan, Zheng return NULL; 4427ae92e74SYan, Zheng 4437ae92e74SYan, Zheng file = fopen(path, "r"); 4447ae92e74SYan, Zheng if (!file) 4457ae92e74SYan, Zheng return NULL; 4467ae92e74SYan, Zheng 4477ae92e74SYan, Zheng cpus = cpu_map__read(file); 4487ae92e74SYan, Zheng fclose(file); 4497ae92e74SYan, Zheng return cpus; 4507ae92e74SYan, Zheng } 4517ae92e74SYan, Zheng 452c5de47f2SSukadev Bhattiprolu struct perf_event_attr * __weak 453dc0a6202SAdrian Hunter perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 454dc0a6202SAdrian Hunter { 455dc0a6202SAdrian Hunter return NULL; 456dc0a6202SAdrian Hunter } 457dc0a6202SAdrian Hunter 458b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_lookup(const char *name) 459cd82a32eSJiri Olsa { 460cd82a32eSJiri Olsa struct perf_pmu *pmu; 461cd82a32eSJiri Olsa LIST_HEAD(format); 462a6146d50SZheng Yan LIST_HEAD(aliases); 463cd82a32eSJiri Olsa __u32 type; 464cd82a32eSJiri Olsa 4659b5d1c29SAdrian Hunter /* No support for intel_bts or intel_pt so disallow them */ 4669b5d1c29SAdrian Hunter if (!strcmp(name, "intel_bts") || !strcmp(name, "intel_pt")) 4679b5d1c29SAdrian Hunter return NULL; 4689b5d1c29SAdrian Hunter 469cd82a32eSJiri Olsa /* 470cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 471cd82a32eSJiri Olsa * type value and format definitions. Load both right 472cd82a32eSJiri Olsa * now. 473cd82a32eSJiri Olsa */ 474cd82a32eSJiri Olsa if (pmu_format(name, &format)) 475cd82a32eSJiri Olsa return NULL; 476cd82a32eSJiri Olsa 4773fded963SJiri Olsa if (pmu_aliases(name, &aliases)) 4783fded963SJiri Olsa return NULL; 4793fded963SJiri Olsa 480cd82a32eSJiri Olsa if (pmu_type(name, &type)) 481cd82a32eSJiri Olsa return NULL; 482cd82a32eSJiri Olsa 483cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 484cd82a32eSJiri Olsa if (!pmu) 485cd82a32eSJiri Olsa return NULL; 486cd82a32eSJiri Olsa 4877ae92e74SYan, Zheng pmu->cpus = pmu_cpumask(name); 4887ae92e74SYan, Zheng 489cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 490a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 491cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 492a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 493cd82a32eSJiri Olsa pmu->name = strdup(name); 494cd82a32eSJiri Olsa pmu->type = type; 4959bc8f9feSRobert Richter list_add_tail(&pmu->list, &pmus); 496dc0a6202SAdrian Hunter 497dc0a6202SAdrian Hunter pmu->default_config = perf_pmu__get_default_config(pmu); 498dc0a6202SAdrian Hunter 499cd82a32eSJiri Olsa return pmu; 500cd82a32eSJiri Olsa } 501cd82a32eSJiri Olsa 502b6b96fb4SAdrian Hunter static struct perf_pmu *pmu_find(const char *name) 503cd82a32eSJiri Olsa { 504cd82a32eSJiri Olsa struct perf_pmu *pmu; 505cd82a32eSJiri Olsa 506cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 507cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 508cd82a32eSJiri Olsa return pmu; 509cd82a32eSJiri Olsa 510cd82a32eSJiri Olsa return NULL; 511cd82a32eSJiri Olsa } 512cd82a32eSJiri Olsa 51350a9667cSRobert Richter struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) 51450a9667cSRobert Richter { 51550a9667cSRobert Richter /* 51650a9667cSRobert Richter * pmu iterator: If pmu is NULL, we start at the begin, 51750a9667cSRobert Richter * otherwise return the next pmu. Returns NULL on end. 51850a9667cSRobert Richter */ 51950a9667cSRobert Richter if (!pmu) { 52050a9667cSRobert Richter pmu_read_sysfs(); 52150a9667cSRobert Richter pmu = list_prepare_entry(pmu, &pmus, list); 52250a9667cSRobert Richter } 52350a9667cSRobert Richter list_for_each_entry_continue(pmu, &pmus, list) 52450a9667cSRobert Richter return pmu; 52550a9667cSRobert Richter return NULL; 52650a9667cSRobert Richter } 52750a9667cSRobert Richter 528b6b96fb4SAdrian Hunter struct perf_pmu *perf_pmu__find(const char *name) 529cd82a32eSJiri Olsa { 530cd82a32eSJiri Olsa struct perf_pmu *pmu; 531cd82a32eSJiri Olsa 532cd82a32eSJiri Olsa /* 533cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 534cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 535cd82a32eSJiri Olsa * the pmu format definitions. 536cd82a32eSJiri Olsa */ 537cd82a32eSJiri Olsa pmu = pmu_find(name); 538cd82a32eSJiri Olsa if (pmu) 539cd82a32eSJiri Olsa return pmu; 540cd82a32eSJiri Olsa 541cd82a32eSJiri Olsa return pmu_lookup(name); 542cd82a32eSJiri Olsa } 543cd82a32eSJiri Olsa 5445c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_format * 54509ff6071SAdrian Hunter pmu_find_format(struct list_head *formats, const char *name) 546cd82a32eSJiri Olsa { 5475c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 548cd82a32eSJiri Olsa 549cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 550cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 551cd82a32eSJiri Olsa return format; 552cd82a32eSJiri Olsa 553cd82a32eSJiri Olsa return NULL; 554cd82a32eSJiri Olsa } 555cd82a32eSJiri Olsa 55609ff6071SAdrian Hunter __u64 perf_pmu__format_bits(struct list_head *formats, const char *name) 55709ff6071SAdrian Hunter { 55809ff6071SAdrian Hunter struct perf_pmu_format *format = pmu_find_format(formats, name); 55909ff6071SAdrian Hunter __u64 bits = 0; 56009ff6071SAdrian Hunter int fbit; 56109ff6071SAdrian Hunter 56209ff6071SAdrian Hunter if (!format) 56309ff6071SAdrian Hunter return 0; 56409ff6071SAdrian Hunter 56509ff6071SAdrian Hunter for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS) 56609ff6071SAdrian Hunter bits |= 1ULL << fbit; 56709ff6071SAdrian Hunter 56809ff6071SAdrian Hunter return bits; 56909ff6071SAdrian Hunter } 57009ff6071SAdrian Hunter 571cd82a32eSJiri Olsa /* 572dc0a6202SAdrian Hunter * Sets value based on the format definition (format parameter) 573cd82a32eSJiri Olsa * and unformated value (value parameter). 574cd82a32eSJiri Olsa */ 575dc0a6202SAdrian Hunter static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, 576dc0a6202SAdrian Hunter bool zero) 577cd82a32eSJiri Olsa { 578cd82a32eSJiri Olsa unsigned long fbit, vbit; 579cd82a32eSJiri Olsa 580cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 581cd82a32eSJiri Olsa 582cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 583cd82a32eSJiri Olsa continue; 584cd82a32eSJiri Olsa 585dc0a6202SAdrian Hunter if (value & (1llu << vbit++)) 586dc0a6202SAdrian Hunter *v |= (1llu << fbit); 587dc0a6202SAdrian Hunter else if (zero) 588dc0a6202SAdrian Hunter *v &= ~(1llu << fbit); 589cd82a32eSJiri Olsa } 590cd82a32eSJiri Olsa } 591cd82a32eSJiri Olsa 592cd82a32eSJiri Olsa /* 593688d4dfcSCody P Schafer * Term is a string term, and might be a param-term. Try to look up it's value 594688d4dfcSCody P Schafer * in the remaining terms. 595688d4dfcSCody P Schafer * - We have a term like "base-or-format-term=param-term", 596688d4dfcSCody P Schafer * - We need to find the value supplied for "param-term" (with param-term named 597688d4dfcSCody P Schafer * in a config string) later on in the term list. 598688d4dfcSCody P Schafer */ 599688d4dfcSCody P Schafer static int pmu_resolve_param_term(struct parse_events_term *term, 600688d4dfcSCody P Schafer struct list_head *head_terms, 601688d4dfcSCody P Schafer __u64 *value) 602688d4dfcSCody P Schafer { 603688d4dfcSCody P Schafer struct parse_events_term *t; 604688d4dfcSCody P Schafer 605688d4dfcSCody P Schafer list_for_each_entry(t, head_terms, list) { 606688d4dfcSCody P Schafer if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 607688d4dfcSCody P Schafer if (!strcmp(t->config, term->config)) { 608688d4dfcSCody P Schafer t->used = true; 609688d4dfcSCody P Schafer *value = t->val.num; 610688d4dfcSCody P Schafer return 0; 611688d4dfcSCody P Schafer } 612688d4dfcSCody P Schafer } 613688d4dfcSCody P Schafer } 614688d4dfcSCody P Schafer 615688d4dfcSCody P Schafer if (verbose) 616688d4dfcSCody P Schafer printf("Required parameter '%s' not specified\n", term->config); 617688d4dfcSCody P Schafer 618688d4dfcSCody P Schafer return -1; 619688d4dfcSCody P Schafer } 620688d4dfcSCody P Schafer 621e64b020bSJiri Olsa static char *formats_error_string(struct list_head *formats) 622e64b020bSJiri Olsa { 623e64b020bSJiri Olsa struct perf_pmu_format *format; 624e64b020bSJiri Olsa char *err, *str; 62532067712SKan Liang static const char *static_terms = "config,config1,config2,name,period,branch_type,time\n"; 626e64b020bSJiri Olsa unsigned i = 0; 627e64b020bSJiri Olsa 628e64b020bSJiri Olsa if (!asprintf(&str, "valid terms:")) 629e64b020bSJiri Olsa return NULL; 630e64b020bSJiri Olsa 631e64b020bSJiri Olsa /* sysfs exported terms */ 632e64b020bSJiri Olsa list_for_each_entry(format, formats, list) { 633e64b020bSJiri Olsa char c = i++ ? ',' : ' '; 634e64b020bSJiri Olsa 635e64b020bSJiri Olsa err = str; 636e64b020bSJiri Olsa if (!asprintf(&str, "%s%c%s", err, c, format->name)) 637e64b020bSJiri Olsa goto fail; 638e64b020bSJiri Olsa free(err); 639e64b020bSJiri Olsa } 640e64b020bSJiri Olsa 641e64b020bSJiri Olsa /* static terms */ 642e64b020bSJiri Olsa err = str; 643e64b020bSJiri Olsa if (!asprintf(&str, "%s,%s", err, static_terms)) 644e64b020bSJiri Olsa goto fail; 645e64b020bSJiri Olsa 646e64b020bSJiri Olsa free(err); 647e64b020bSJiri Olsa return str; 648e64b020bSJiri Olsa fail: 649e64b020bSJiri Olsa free(err); 650e64b020bSJiri Olsa return NULL; 651e64b020bSJiri Olsa } 652e64b020bSJiri Olsa 653688d4dfcSCody P Schafer /* 654cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 65588aca8d9SCody P Schafer * user input data - term parameter. 656cd82a32eSJiri Olsa */ 657cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 658cd82a32eSJiri Olsa struct perf_event_attr *attr, 659dc0a6202SAdrian Hunter struct parse_events_term *term, 660688d4dfcSCody P Schafer struct list_head *head_terms, 661e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 662cd82a32eSJiri Olsa { 6635c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 664cd82a32eSJiri Olsa __u64 *vp; 665688d4dfcSCody P Schafer __u64 val; 666cd82a32eSJiri Olsa 667cd82a32eSJiri Olsa /* 668688d4dfcSCody P Schafer * If this is a parameter we've already used for parameterized-eval, 669688d4dfcSCody P Schafer * skip it in normal eval. 670688d4dfcSCody P Schafer */ 671688d4dfcSCody P Schafer if (term->used) 672688d4dfcSCody P Schafer return 0; 673688d4dfcSCody P Schafer 674688d4dfcSCody P Schafer /* 675cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 676cd82a32eSJiri Olsa * to be done for them. 677cd82a32eSJiri Olsa */ 678cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 679cd82a32eSJiri Olsa return 0; 680cd82a32eSJiri Olsa 681cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 682688d4dfcSCody P Schafer if (!format) { 683688d4dfcSCody P Schafer if (verbose) 684688d4dfcSCody P Schafer printf("Invalid event/parameter '%s'\n", term->config); 685e64b020bSJiri Olsa if (err) { 686e64b020bSJiri Olsa err->idx = term->err_term; 687e64b020bSJiri Olsa err->str = strdup("unknown term"); 688e64b020bSJiri Olsa err->help = formats_error_string(formats); 689e64b020bSJiri Olsa } 690cd82a32eSJiri Olsa return -EINVAL; 691688d4dfcSCody P Schafer } 692cd82a32eSJiri Olsa 693cd82a32eSJiri Olsa switch (format->value) { 694cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 695cd82a32eSJiri Olsa vp = &attr->config; 696cd82a32eSJiri Olsa break; 697cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 698cd82a32eSJiri Olsa vp = &attr->config1; 699cd82a32eSJiri Olsa break; 700cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 701cd82a32eSJiri Olsa vp = &attr->config2; 702cd82a32eSJiri Olsa break; 703cd82a32eSJiri Olsa default: 704cd82a32eSJiri Olsa return -EINVAL; 705cd82a32eSJiri Olsa } 706cd82a32eSJiri Olsa 70716fa7e82SJiri Olsa /* 708688d4dfcSCody P Schafer * Either directly use a numeric term, or try to translate string terms 709688d4dfcSCody P Schafer * using event parameters. 71016fa7e82SJiri Olsa */ 711688d4dfcSCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) 712688d4dfcSCody P Schafer val = term->val.num; 713688d4dfcSCody P Schafer else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 714688d4dfcSCody P Schafer if (strcmp(term->val.str, "?")) { 715e64b020bSJiri Olsa if (verbose) { 716688d4dfcSCody P Schafer pr_info("Invalid sysfs entry %s=%s\n", 717688d4dfcSCody P Schafer term->config, term->val.str); 718e64b020bSJiri Olsa } 719e64b020bSJiri Olsa if (err) { 720e64b020bSJiri Olsa err->idx = term->err_val; 721e64b020bSJiri Olsa err->str = strdup("expected numeric value"); 722e64b020bSJiri Olsa } 723688d4dfcSCody P Schafer return -EINVAL; 724688d4dfcSCody P Schafer } 725688d4dfcSCody P Schafer 726688d4dfcSCody P Schafer if (pmu_resolve_param_term(term, head_terms, &val)) 727688d4dfcSCody P Schafer return -EINVAL; 728688d4dfcSCody P Schafer } else 729688d4dfcSCody P Schafer return -EINVAL; 730688d4dfcSCody P Schafer 731688d4dfcSCody P Schafer pmu_format_value(format->bits, val, vp, zero); 732cd82a32eSJiri Olsa return 0; 733cd82a32eSJiri Olsa } 734cd82a32eSJiri Olsa 735cff7f956SJiri Olsa int perf_pmu__config_terms(struct list_head *formats, 736cff7f956SJiri Olsa struct perf_event_attr *attr, 737dc0a6202SAdrian Hunter struct list_head *head_terms, 738e64b020bSJiri Olsa bool zero, struct parse_events_error *err) 739cd82a32eSJiri Olsa { 7406cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term; 741cd82a32eSJiri Olsa 742688d4dfcSCody P Schafer list_for_each_entry(term, head_terms, list) { 743e64b020bSJiri Olsa if (pmu_config_term(formats, attr, term, head_terms, 744e64b020bSJiri Olsa zero, err)) 745cd82a32eSJiri Olsa return -EINVAL; 746688d4dfcSCody P Schafer } 747cd82a32eSJiri Olsa 748cd82a32eSJiri Olsa return 0; 749cd82a32eSJiri Olsa } 750cd82a32eSJiri Olsa 751cd82a32eSJiri Olsa /* 752cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 753cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 754cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 755cd82a32eSJiri Olsa */ 756cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 757e64b020bSJiri Olsa struct list_head *head_terms, 758e64b020bSJiri Olsa struct parse_events_error *err) 759cd82a32eSJiri Olsa { 760dc0a6202SAdrian Hunter bool zero = !!pmu->default_config; 761dc0a6202SAdrian Hunter 762cd82a32eSJiri Olsa attr->type = pmu->type; 763e64b020bSJiri Olsa return perf_pmu__config_terms(&pmu->format, attr, head_terms, 764e64b020bSJiri Olsa zero, err); 765cd82a32eSJiri Olsa } 766cd82a32eSJiri Olsa 7675c6ccc37SArnaldo Carvalho de Melo static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 7686cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term) 769a6146d50SZheng Yan { 7705c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 771a6146d50SZheng Yan char *name; 772a6146d50SZheng Yan 773a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 774a6146d50SZheng Yan return NULL; 775a6146d50SZheng Yan 776a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 777a6146d50SZheng Yan if (term->val.num != 1) 778a6146d50SZheng Yan return NULL; 779a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 780a6146d50SZheng Yan return NULL; 781a6146d50SZheng Yan name = term->config; 782a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 783a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 784a6146d50SZheng Yan return NULL; 785a6146d50SZheng Yan name = term->val.str; 786a6146d50SZheng Yan } else { 787a6146d50SZheng Yan return NULL; 788a6146d50SZheng Yan } 789a6146d50SZheng Yan 790a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 791a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 792a6146d50SZheng Yan return alias; 793a6146d50SZheng Yan } 794a6146d50SZheng Yan return NULL; 795a6146d50SZheng Yan } 796a6146d50SZheng Yan 797410136f5SStephane Eranian 7981d9e446bSJiri Olsa static int check_info_data(struct perf_pmu_alias *alias, 7991d9e446bSJiri Olsa struct perf_pmu_info *info) 800410136f5SStephane Eranian { 801410136f5SStephane Eranian /* 802410136f5SStephane Eranian * Only one term in event definition can 8031d9e446bSJiri Olsa * define unit, scale and snapshot, fail 8041d9e446bSJiri Olsa * if there's more than one. 805410136f5SStephane Eranian */ 8061d9e446bSJiri Olsa if ((info->unit && alias->unit) || 8071d9e446bSJiri Olsa (info->scale && alias->scale) || 8081d9e446bSJiri Olsa (info->snapshot && alias->snapshot)) 809410136f5SStephane Eranian return -EINVAL; 810410136f5SStephane Eranian 811410136f5SStephane Eranian if (alias->unit) 8121d9e446bSJiri Olsa info->unit = alias->unit; 813410136f5SStephane Eranian 814410136f5SStephane Eranian if (alias->scale) 8151d9e446bSJiri Olsa info->scale = alias->scale; 8161d9e446bSJiri Olsa 8171d9e446bSJiri Olsa if (alias->snapshot) 8181d9e446bSJiri Olsa info->snapshot = alias->snapshot; 819410136f5SStephane Eranian 820410136f5SStephane Eranian return 0; 821410136f5SStephane Eranian } 822410136f5SStephane Eranian 823a6146d50SZheng Yan /* 824a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 825a6146d50SZheng Yan * defined for the alias 826a6146d50SZheng Yan */ 827410136f5SStephane Eranian int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 82846441bdcSMatt Fleming struct perf_pmu_info *info) 829a6146d50SZheng Yan { 8306cee6cd3SArnaldo Carvalho de Melo struct parse_events_term *term, *h; 8315c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_alias *alias; 832a6146d50SZheng Yan int ret; 833a6146d50SZheng Yan 834044330c1SMatt Fleming info->per_pkg = false; 835044330c1SMatt Fleming 8368a398897SStephane Eranian /* 8378a398897SStephane Eranian * Mark unit and scale as not set 8388a398897SStephane Eranian * (different from default values, see below) 8398a398897SStephane Eranian */ 84046441bdcSMatt Fleming info->unit = NULL; 84146441bdcSMatt Fleming info->scale = 0.0; 8421d9e446bSJiri Olsa info->snapshot = false; 843410136f5SStephane Eranian 844a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 845a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 846a6146d50SZheng Yan if (!alias) 847a6146d50SZheng Yan continue; 848a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 849a6146d50SZheng Yan if (ret) 850a6146d50SZheng Yan return ret; 851410136f5SStephane Eranian 8521d9e446bSJiri Olsa ret = check_info_data(alias, info); 853410136f5SStephane Eranian if (ret) 854410136f5SStephane Eranian return ret; 855410136f5SStephane Eranian 856044330c1SMatt Fleming if (alias->per_pkg) 857044330c1SMatt Fleming info->per_pkg = true; 858044330c1SMatt Fleming 859a6146d50SZheng Yan list_del(&term->list); 860a6146d50SZheng Yan free(term); 861a6146d50SZheng Yan } 8628a398897SStephane Eranian 8638a398897SStephane Eranian /* 8648a398897SStephane Eranian * if no unit or scale foundin aliases, then 8658a398897SStephane Eranian * set defaults as for evsel 8668a398897SStephane Eranian * unit cannot left to NULL 8678a398897SStephane Eranian */ 86846441bdcSMatt Fleming if (info->unit == NULL) 86946441bdcSMatt Fleming info->unit = ""; 8708a398897SStephane Eranian 87146441bdcSMatt Fleming if (info->scale == 0.0) 87246441bdcSMatt Fleming info->scale = 1.0; 8738a398897SStephane Eranian 874a6146d50SZheng Yan return 0; 875a6146d50SZheng Yan } 876a6146d50SZheng Yan 877cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 878cd82a32eSJiri Olsa int config, unsigned long *bits) 879cd82a32eSJiri Olsa { 8805c6ccc37SArnaldo Carvalho de Melo struct perf_pmu_format *format; 881cd82a32eSJiri Olsa 882cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 883cd82a32eSJiri Olsa if (!format) 884cd82a32eSJiri Olsa return -ENOMEM; 885cd82a32eSJiri Olsa 886cd82a32eSJiri Olsa format->name = strdup(name); 887cd82a32eSJiri Olsa format->value = config; 888cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 889cd82a32eSJiri Olsa 890cd82a32eSJiri Olsa list_add_tail(&format->list, list); 891cd82a32eSJiri Olsa return 0; 892cd82a32eSJiri Olsa } 893cd82a32eSJiri Olsa 894cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 895cd82a32eSJiri Olsa { 896cd82a32eSJiri Olsa long b; 897cd82a32eSJiri Olsa 898cd82a32eSJiri Olsa if (!to) 899cd82a32eSJiri Olsa to = from; 900cd82a32eSJiri Olsa 90115268138SSukadev Bhattiprolu memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS)); 902cd82a32eSJiri Olsa for (b = from; b <= to; b++) 903cd82a32eSJiri Olsa set_bit(b, bits); 904cd82a32eSJiri Olsa } 905dc098b35SAndi Kleen 906aaea3617SCody P Schafer static int sub_non_neg(int a, int b) 907aaea3617SCody P Schafer { 908aaea3617SCody P Schafer if (b > a) 909aaea3617SCody P Schafer return 0; 910aaea3617SCody P Schafer return a - b; 911aaea3617SCody P Schafer } 912aaea3617SCody P Schafer 913dc098b35SAndi Kleen static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 914dc098b35SAndi Kleen struct perf_pmu_alias *alias) 915dc098b35SAndi Kleen { 916aaea3617SCody P Schafer struct parse_events_term *term; 917aaea3617SCody P Schafer int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name); 918aaea3617SCody P Schafer 919aaea3617SCody P Schafer list_for_each_entry(term, &alias->terms, list) { 920aaea3617SCody P Schafer if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) 921aaea3617SCody P Schafer used += snprintf(buf + used, sub_non_neg(len, used), 922aaea3617SCody P Schafer ",%s=%s", term->config, 923aaea3617SCody P Schafer term->val.str); 924aaea3617SCody P Schafer } 925aaea3617SCody P Schafer 926aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 927aaea3617SCody P Schafer buf[used] = '/'; 928aaea3617SCody P Schafer used++; 929aaea3617SCody P Schafer } 930aaea3617SCody P Schafer if (sub_non_neg(len, used) > 0) { 931aaea3617SCody P Schafer buf[used] = '\0'; 932aaea3617SCody P Schafer used++; 933aaea3617SCody P Schafer } else 934aaea3617SCody P Schafer buf[len - 1] = '\0'; 935aaea3617SCody P Schafer 936dc098b35SAndi Kleen return buf; 937dc098b35SAndi Kleen } 938dc098b35SAndi Kleen 939dc098b35SAndi Kleen static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, 940dc098b35SAndi Kleen struct perf_pmu_alias *alias) 941dc098b35SAndi Kleen { 942dc098b35SAndi Kleen snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); 943dc098b35SAndi Kleen return buf; 944dc098b35SAndi Kleen } 945dc098b35SAndi Kleen 946dc098b35SAndi Kleen static int cmp_string(const void *a, const void *b) 947dc098b35SAndi Kleen { 948dc098b35SAndi Kleen const char * const *as = a; 949dc098b35SAndi Kleen const char * const *bs = b; 950dc098b35SAndi Kleen return strcmp(*as, *bs); 951dc098b35SAndi Kleen } 952dc098b35SAndi Kleen 953dc098b35SAndi Kleen void print_pmu_events(const char *event_glob, bool name_only) 954dc098b35SAndi Kleen { 955dc098b35SAndi Kleen struct perf_pmu *pmu; 956dc098b35SAndi Kleen struct perf_pmu_alias *alias; 957dc098b35SAndi Kleen char buf[1024]; 958dc098b35SAndi Kleen int printed = 0; 959dc098b35SAndi Kleen int len, j; 960dc098b35SAndi Kleen char **aliases; 961dc098b35SAndi Kleen 962dc098b35SAndi Kleen pmu = NULL; 963dc098b35SAndi Kleen len = 0; 96442634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 965dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 966dc098b35SAndi Kleen len++; 96742634bc7SAdrian Hunter if (pmu->selectable) 96842634bc7SAdrian Hunter len++; 96942634bc7SAdrian Hunter } 9707e4772dcSArnaldo Carvalho de Melo aliases = zalloc(sizeof(char *) * len); 971dc098b35SAndi Kleen if (!aliases) 9727e4772dcSArnaldo Carvalho de Melo goto out_enomem; 973dc098b35SAndi Kleen pmu = NULL; 974dc098b35SAndi Kleen j = 0; 97542634bc7SAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 976dc098b35SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) { 977dc098b35SAndi Kleen char *name = format_alias(buf, sizeof(buf), pmu, alias); 978dc098b35SAndi Kleen bool is_cpu = !strcmp(pmu->name, "cpu"); 979dc098b35SAndi Kleen 980dc098b35SAndi Kleen if (event_glob != NULL && 981dc098b35SAndi Kleen !(strglobmatch(name, event_glob) || 982dc098b35SAndi Kleen (!is_cpu && strglobmatch(alias->name, 983dc098b35SAndi Kleen event_glob)))) 984dc098b35SAndi Kleen continue; 9857e4772dcSArnaldo Carvalho de Melo 986dc098b35SAndi Kleen if (is_cpu && !name_only) 9877e4772dcSArnaldo Carvalho de Melo name = format_alias_or(buf, sizeof(buf), pmu, alias); 9887e4772dcSArnaldo Carvalho de Melo 9897e4772dcSArnaldo Carvalho de Melo aliases[j] = strdup(name); 9907e4772dcSArnaldo Carvalho de Melo if (aliases[j] == NULL) 9917e4772dcSArnaldo Carvalho de Melo goto out_enomem; 992dc098b35SAndi Kleen j++; 993dc098b35SAndi Kleen } 99442634bc7SAdrian Hunter if (pmu->selectable) { 9957e4772dcSArnaldo Carvalho de Melo char *s; 9967e4772dcSArnaldo Carvalho de Melo if (asprintf(&s, "%s//", pmu->name) < 0) 9977e4772dcSArnaldo Carvalho de Melo goto out_enomem; 9987e4772dcSArnaldo Carvalho de Melo aliases[j] = s; 99942634bc7SAdrian Hunter j++; 100042634bc7SAdrian Hunter } 100142634bc7SAdrian Hunter } 1002dc098b35SAndi Kleen len = j; 1003dc098b35SAndi Kleen qsort(aliases, len, sizeof(char *), cmp_string); 1004dc098b35SAndi Kleen for (j = 0; j < len; j++) { 1005dc098b35SAndi Kleen if (name_only) { 1006dc098b35SAndi Kleen printf("%s ", aliases[j]); 1007dc098b35SAndi Kleen continue; 1008dc098b35SAndi Kleen } 1009dc098b35SAndi Kleen printf(" %-50s [Kernel PMU event]\n", aliases[j]); 1010dc098b35SAndi Kleen printed++; 1011dc098b35SAndi Kleen } 1012dc098b35SAndi Kleen if (printed) 1013dc098b35SAndi Kleen printf("\n"); 10147e4772dcSArnaldo Carvalho de Melo out_free: 10157e4772dcSArnaldo Carvalho de Melo for (j = 0; j < len; j++) 10167e4772dcSArnaldo Carvalho de Melo zfree(&aliases[j]); 10177e4772dcSArnaldo Carvalho de Melo zfree(&aliases); 10187e4772dcSArnaldo Carvalho de Melo return; 10197e4772dcSArnaldo Carvalho de Melo 10207e4772dcSArnaldo Carvalho de Melo out_enomem: 10217e4772dcSArnaldo Carvalho de Melo printf("FATAL: not enough memory to print PMU events\n"); 10227e4772dcSArnaldo Carvalho de Melo if (aliases) 10237e4772dcSArnaldo Carvalho de Melo goto out_free; 1024dc098b35SAndi Kleen } 10254cabc3d1SAndi Kleen 10264cabc3d1SAndi Kleen bool pmu_have_event(const char *pname, const char *name) 10274cabc3d1SAndi Kleen { 10284cabc3d1SAndi Kleen struct perf_pmu *pmu; 10294cabc3d1SAndi Kleen struct perf_pmu_alias *alias; 10304cabc3d1SAndi Kleen 10314cabc3d1SAndi Kleen pmu = NULL; 10324cabc3d1SAndi Kleen while ((pmu = perf_pmu__scan(pmu)) != NULL) { 10334cabc3d1SAndi Kleen if (strcmp(pname, pmu->name)) 10344cabc3d1SAndi Kleen continue; 10354cabc3d1SAndi Kleen list_for_each_entry(alias, &pmu->aliases, list) 10364cabc3d1SAndi Kleen if (!strcmp(alias->name, name)) 10374cabc3d1SAndi Kleen return true; 10384cabc3d1SAndi Kleen } 10394cabc3d1SAndi Kleen return false; 10404cabc3d1SAndi Kleen } 10417d4bdab5SAdrian Hunter 10427d4bdab5SAdrian Hunter static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) 10437d4bdab5SAdrian Hunter { 10447d4bdab5SAdrian Hunter struct stat st; 10457d4bdab5SAdrian Hunter char path[PATH_MAX]; 10467d4bdab5SAdrian Hunter const char *sysfs; 10477d4bdab5SAdrian Hunter 10487d4bdab5SAdrian Hunter sysfs = sysfs__mountpoint(); 10497d4bdab5SAdrian Hunter if (!sysfs) 10507d4bdab5SAdrian Hunter return NULL; 10517d4bdab5SAdrian Hunter 10527d4bdab5SAdrian Hunter snprintf(path, PATH_MAX, 10537d4bdab5SAdrian Hunter "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); 10547d4bdab5SAdrian Hunter 10557d4bdab5SAdrian Hunter if (stat(path, &st) < 0) 10567d4bdab5SAdrian Hunter return NULL; 10577d4bdab5SAdrian Hunter 10587d4bdab5SAdrian Hunter return fopen(path, "r"); 10597d4bdab5SAdrian Hunter } 10607d4bdab5SAdrian Hunter 10617d4bdab5SAdrian Hunter int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 10627d4bdab5SAdrian Hunter ...) 10637d4bdab5SAdrian Hunter { 10647d4bdab5SAdrian Hunter va_list args; 10657d4bdab5SAdrian Hunter FILE *file; 10667d4bdab5SAdrian Hunter int ret = EOF; 10677d4bdab5SAdrian Hunter 10687d4bdab5SAdrian Hunter va_start(args, fmt); 10697d4bdab5SAdrian Hunter file = perf_pmu__open_file(pmu, name); 10707d4bdab5SAdrian Hunter if (file) { 10717d4bdab5SAdrian Hunter ret = vfscanf(file, fmt, args); 10727d4bdab5SAdrian Hunter fclose(file); 10737d4bdab5SAdrian Hunter } 10747d4bdab5SAdrian Hunter va_end(args); 10757d4bdab5SAdrian Hunter return ret; 10767d4bdab5SAdrian Hunter } 1077