1cd82a32eSJiri Olsa 2cd82a32eSJiri Olsa #include <linux/list.h> 3cd82a32eSJiri Olsa #include <sys/types.h> 4cd82a32eSJiri Olsa #include <sys/stat.h> 5cd82a32eSJiri Olsa #include <unistd.h> 6cd82a32eSJiri Olsa #include <stdio.h> 7cd82a32eSJiri Olsa #include <dirent.h> 8cd82a32eSJiri Olsa #include "sysfs.h" 9cd82a32eSJiri Olsa #include "util.h" 10cd82a32eSJiri Olsa #include "pmu.h" 11cd82a32eSJiri Olsa #include "parse-events.h" 12cd82a32eSJiri Olsa 13cd82a32eSJiri Olsa int perf_pmu_parse(struct list_head *list, char *name); 14cd82a32eSJiri Olsa extern FILE *perf_pmu_in; 15cd82a32eSJiri Olsa 16cd82a32eSJiri Olsa static LIST_HEAD(pmus); 17cd82a32eSJiri Olsa 18cd82a32eSJiri Olsa /* 19cd82a32eSJiri Olsa * Parse & process all the sysfs attributes located under 20cd82a32eSJiri Olsa * the directory specified in 'dir' parameter. 21cd82a32eSJiri Olsa */ 22cd82a32eSJiri Olsa static int pmu_format_parse(char *dir, struct list_head *head) 23cd82a32eSJiri Olsa { 24cd82a32eSJiri Olsa struct dirent *evt_ent; 25cd82a32eSJiri Olsa DIR *format_dir; 26cd82a32eSJiri Olsa int ret = 0; 27cd82a32eSJiri Olsa 28cd82a32eSJiri Olsa format_dir = opendir(dir); 29cd82a32eSJiri Olsa if (!format_dir) 30cd82a32eSJiri Olsa return -EINVAL; 31cd82a32eSJiri Olsa 32cd82a32eSJiri Olsa while (!ret && (evt_ent = readdir(format_dir))) { 33cd82a32eSJiri Olsa char path[PATH_MAX]; 34cd82a32eSJiri Olsa char *name = evt_ent->d_name; 35cd82a32eSJiri Olsa FILE *file; 36cd82a32eSJiri Olsa 37cd82a32eSJiri Olsa if (!strcmp(name, ".") || !strcmp(name, "..")) 38cd82a32eSJiri Olsa continue; 39cd82a32eSJiri Olsa 40cd82a32eSJiri Olsa snprintf(path, PATH_MAX, "%s/%s", dir, name); 41cd82a32eSJiri Olsa 42cd82a32eSJiri Olsa ret = -EINVAL; 43cd82a32eSJiri Olsa file = fopen(path, "r"); 44cd82a32eSJiri Olsa if (!file) 45cd82a32eSJiri Olsa break; 46cd82a32eSJiri Olsa 47cd82a32eSJiri Olsa perf_pmu_in = file; 48cd82a32eSJiri Olsa ret = perf_pmu_parse(head, name); 49cd82a32eSJiri Olsa fclose(file); 50cd82a32eSJiri Olsa } 51cd82a32eSJiri Olsa 52cd82a32eSJiri Olsa closedir(format_dir); 53cd82a32eSJiri Olsa return ret; 54cd82a32eSJiri Olsa } 55cd82a32eSJiri Olsa 56cd82a32eSJiri Olsa /* 57cd82a32eSJiri Olsa * Reading/parsing the default pmu format definition, which should be 58cd82a32eSJiri Olsa * located at: 59cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. 60cd82a32eSJiri Olsa */ 61cd82a32eSJiri Olsa static int pmu_format(char *name, struct list_head *format) 62cd82a32eSJiri Olsa { 63cd82a32eSJiri Olsa struct stat st; 64cd82a32eSJiri Olsa char path[PATH_MAX]; 65cd82a32eSJiri Olsa const char *sysfs; 66cd82a32eSJiri Olsa 67cd82a32eSJiri Olsa sysfs = sysfs_find_mountpoint(); 68cd82a32eSJiri Olsa if (!sysfs) 69cd82a32eSJiri Olsa return -1; 70cd82a32eSJiri Olsa 71cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 72cd82a32eSJiri Olsa "%s/bus/event_source/devices/%s/format", sysfs, name); 73cd82a32eSJiri Olsa 74cd82a32eSJiri Olsa if (stat(path, &st) < 0) 75cd82a32eSJiri Olsa return -1; 76cd82a32eSJiri Olsa 77cd82a32eSJiri Olsa if (pmu_format_parse(path, format)) 78cd82a32eSJiri Olsa return -1; 79cd82a32eSJiri Olsa 80cd82a32eSJiri Olsa return 0; 81cd82a32eSJiri Olsa } 82cd82a32eSJiri Olsa 83a6146d50SZheng Yan static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 84a6146d50SZheng Yan { 85a6146d50SZheng Yan struct perf_pmu__alias *alias; 86a6146d50SZheng Yan char buf[256]; 87a6146d50SZheng Yan int ret; 88a6146d50SZheng Yan 89a6146d50SZheng Yan ret = fread(buf, 1, sizeof(buf), file); 90a6146d50SZheng Yan if (ret == 0) 91a6146d50SZheng Yan return -EINVAL; 92a6146d50SZheng Yan buf[ret] = 0; 93a6146d50SZheng Yan 94a6146d50SZheng Yan alias = malloc(sizeof(*alias)); 95a6146d50SZheng Yan if (!alias) 96a6146d50SZheng Yan return -ENOMEM; 97a6146d50SZheng Yan 98a6146d50SZheng Yan INIT_LIST_HEAD(&alias->terms); 99a6146d50SZheng Yan ret = parse_events_terms(&alias->terms, buf); 100a6146d50SZheng Yan if (ret) { 101a6146d50SZheng Yan free(alias); 102a6146d50SZheng Yan return ret; 103a6146d50SZheng Yan } 104a6146d50SZheng Yan 105a6146d50SZheng Yan alias->name = strdup(name); 106a6146d50SZheng Yan list_add_tail(&alias->list, list); 107a6146d50SZheng Yan return 0; 108a6146d50SZheng Yan } 109a6146d50SZheng Yan 110a6146d50SZheng Yan /* 111a6146d50SZheng Yan * Process all the sysfs attributes located under the directory 112a6146d50SZheng Yan * specified in 'dir' parameter. 113a6146d50SZheng Yan */ 114a6146d50SZheng Yan static int pmu_aliases_parse(char *dir, struct list_head *head) 115a6146d50SZheng Yan { 116a6146d50SZheng Yan struct dirent *evt_ent; 117a6146d50SZheng Yan DIR *event_dir; 118a6146d50SZheng Yan int ret = 0; 119a6146d50SZheng Yan 120a6146d50SZheng Yan event_dir = opendir(dir); 121a6146d50SZheng Yan if (!event_dir) 122a6146d50SZheng Yan return -EINVAL; 123a6146d50SZheng Yan 124a6146d50SZheng Yan while (!ret && (evt_ent = readdir(event_dir))) { 125a6146d50SZheng Yan char path[PATH_MAX]; 126a6146d50SZheng Yan char *name = evt_ent->d_name; 127a6146d50SZheng Yan FILE *file; 128a6146d50SZheng Yan 129a6146d50SZheng Yan if (!strcmp(name, ".") || !strcmp(name, "..")) 130a6146d50SZheng Yan continue; 131a6146d50SZheng Yan 132a6146d50SZheng Yan snprintf(path, PATH_MAX, "%s/%s", dir, name); 133a6146d50SZheng Yan 134a6146d50SZheng Yan ret = -EINVAL; 135a6146d50SZheng Yan file = fopen(path, "r"); 136a6146d50SZheng Yan if (!file) 137a6146d50SZheng Yan break; 138a6146d50SZheng Yan ret = perf_pmu__new_alias(head, name, file); 139a6146d50SZheng Yan fclose(file); 140a6146d50SZheng Yan } 141a6146d50SZheng Yan 142a6146d50SZheng Yan closedir(event_dir); 143a6146d50SZheng Yan return ret; 144a6146d50SZheng Yan } 145a6146d50SZheng Yan 146a6146d50SZheng Yan /* 147a6146d50SZheng Yan * Reading the pmu event aliases definition, which should be located at: 148a6146d50SZheng Yan * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. 149a6146d50SZheng Yan */ 150a6146d50SZheng Yan static int pmu_aliases(char *name, struct list_head *head) 151a6146d50SZheng Yan { 152a6146d50SZheng Yan struct stat st; 153a6146d50SZheng Yan char path[PATH_MAX]; 154a6146d50SZheng Yan const char *sysfs; 155a6146d50SZheng Yan 156a6146d50SZheng Yan sysfs = sysfs_find_mountpoint(); 157a6146d50SZheng Yan if (!sysfs) 158a6146d50SZheng Yan return -1; 159a6146d50SZheng Yan 160a6146d50SZheng Yan snprintf(path, PATH_MAX, 161a6146d50SZheng Yan "%s/bus/event_source/devices/%s/events", sysfs, name); 162a6146d50SZheng Yan 163a6146d50SZheng Yan if (stat(path, &st) < 0) 164a6146d50SZheng Yan return -1; 165a6146d50SZheng Yan 166a6146d50SZheng Yan if (pmu_aliases_parse(path, head)) 167a6146d50SZheng Yan return -1; 168a6146d50SZheng Yan 169a6146d50SZheng Yan return 0; 170a6146d50SZheng Yan } 171a6146d50SZheng Yan 172a6146d50SZheng Yan static int pmu_alias_terms(struct perf_pmu__alias *alias, 173a6146d50SZheng Yan struct list_head *terms) 174a6146d50SZheng Yan { 175a6146d50SZheng Yan struct parse_events__term *term, *clone; 176a6146d50SZheng Yan LIST_HEAD(list); 177a6146d50SZheng Yan int ret; 178a6146d50SZheng Yan 179a6146d50SZheng Yan list_for_each_entry(term, &alias->terms, list) { 180a6146d50SZheng Yan ret = parse_events__term_clone(&clone, term); 181a6146d50SZheng Yan if (ret) { 182a6146d50SZheng Yan parse_events__free_terms(&list); 183a6146d50SZheng Yan return ret; 184a6146d50SZheng Yan } 185a6146d50SZheng Yan list_add_tail(&clone->list, &list); 186a6146d50SZheng Yan } 187a6146d50SZheng Yan list_splice(&list, terms); 188a6146d50SZheng Yan return 0; 189a6146d50SZheng Yan } 190a6146d50SZheng Yan 191cd82a32eSJiri Olsa /* 192cd82a32eSJiri Olsa * Reading/parsing the default pmu type value, which should be 193cd82a32eSJiri Olsa * located at: 194cd82a32eSJiri Olsa * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. 195cd82a32eSJiri Olsa */ 196cd82a32eSJiri Olsa static int pmu_type(char *name, __u32 *type) 197cd82a32eSJiri Olsa { 198cd82a32eSJiri Olsa struct stat st; 199cd82a32eSJiri Olsa char path[PATH_MAX]; 200cd82a32eSJiri Olsa const char *sysfs; 201cd82a32eSJiri Olsa FILE *file; 202cd82a32eSJiri Olsa int ret = 0; 203cd82a32eSJiri Olsa 204cd82a32eSJiri Olsa sysfs = sysfs_find_mountpoint(); 205cd82a32eSJiri Olsa if (!sysfs) 206cd82a32eSJiri Olsa return -1; 207cd82a32eSJiri Olsa 208cd82a32eSJiri Olsa snprintf(path, PATH_MAX, 209cd82a32eSJiri Olsa "%s/bus/event_source/devices/%s/type", sysfs, name); 210cd82a32eSJiri Olsa 211cd82a32eSJiri Olsa if (stat(path, &st) < 0) 212cd82a32eSJiri Olsa return -1; 213cd82a32eSJiri Olsa 214cd82a32eSJiri Olsa file = fopen(path, "r"); 215cd82a32eSJiri Olsa if (!file) 216cd82a32eSJiri Olsa return -EINVAL; 217cd82a32eSJiri Olsa 218cd82a32eSJiri Olsa if (1 != fscanf(file, "%u", type)) 219cd82a32eSJiri Olsa ret = -1; 220cd82a32eSJiri Olsa 221cd82a32eSJiri Olsa fclose(file); 222cd82a32eSJiri Olsa return ret; 223cd82a32eSJiri Olsa } 224cd82a32eSJiri Olsa 225cd82a32eSJiri Olsa static struct perf_pmu *pmu_lookup(char *name) 226cd82a32eSJiri Olsa { 227cd82a32eSJiri Olsa struct perf_pmu *pmu; 228cd82a32eSJiri Olsa LIST_HEAD(format); 229a6146d50SZheng Yan LIST_HEAD(aliases); 230cd82a32eSJiri Olsa __u32 type; 231cd82a32eSJiri Olsa 232cd82a32eSJiri Olsa /* 233cd82a32eSJiri Olsa * The pmu data we store & need consists of the pmu 234cd82a32eSJiri Olsa * type value and format definitions. Load both right 235cd82a32eSJiri Olsa * now. 236cd82a32eSJiri Olsa */ 237cd82a32eSJiri Olsa if (pmu_format(name, &format)) 238cd82a32eSJiri Olsa return NULL; 239cd82a32eSJiri Olsa 240cd82a32eSJiri Olsa if (pmu_type(name, &type)) 241cd82a32eSJiri Olsa return NULL; 242cd82a32eSJiri Olsa 243cd82a32eSJiri Olsa pmu = zalloc(sizeof(*pmu)); 244cd82a32eSJiri Olsa if (!pmu) 245cd82a32eSJiri Olsa return NULL; 246cd82a32eSJiri Olsa 247a6146d50SZheng Yan pmu_aliases(name, &aliases); 248a6146d50SZheng Yan 249cd82a32eSJiri Olsa INIT_LIST_HEAD(&pmu->format); 250a6146d50SZheng Yan INIT_LIST_HEAD(&pmu->aliases); 251cd82a32eSJiri Olsa list_splice(&format, &pmu->format); 252a6146d50SZheng Yan list_splice(&aliases, &pmu->aliases); 253cd82a32eSJiri Olsa pmu->name = strdup(name); 254cd82a32eSJiri Olsa pmu->type = type; 255cd82a32eSJiri Olsa return pmu; 256cd82a32eSJiri Olsa } 257cd82a32eSJiri Olsa 258cd82a32eSJiri Olsa static struct perf_pmu *pmu_find(char *name) 259cd82a32eSJiri Olsa { 260cd82a32eSJiri Olsa struct perf_pmu *pmu; 261cd82a32eSJiri Olsa 262cd82a32eSJiri Olsa list_for_each_entry(pmu, &pmus, list) 263cd82a32eSJiri Olsa if (!strcmp(pmu->name, name)) 264cd82a32eSJiri Olsa return pmu; 265cd82a32eSJiri Olsa 266cd82a32eSJiri Olsa return NULL; 267cd82a32eSJiri Olsa } 268cd82a32eSJiri Olsa 269cd82a32eSJiri Olsa struct perf_pmu *perf_pmu__find(char *name) 270cd82a32eSJiri Olsa { 271cd82a32eSJiri Olsa struct perf_pmu *pmu; 272cd82a32eSJiri Olsa 273cd82a32eSJiri Olsa /* 274cd82a32eSJiri Olsa * Once PMU is loaded it stays in the list, 275cd82a32eSJiri Olsa * so we keep us from multiple reading/parsing 276cd82a32eSJiri Olsa * the pmu format definitions. 277cd82a32eSJiri Olsa */ 278cd82a32eSJiri Olsa pmu = pmu_find(name); 279cd82a32eSJiri Olsa if (pmu) 280cd82a32eSJiri Olsa return pmu; 281cd82a32eSJiri Olsa 282cd82a32eSJiri Olsa return pmu_lookup(name); 283cd82a32eSJiri Olsa } 284cd82a32eSJiri Olsa 285cd82a32eSJiri Olsa static struct perf_pmu__format* 286cd82a32eSJiri Olsa pmu_find_format(struct list_head *formats, char *name) 287cd82a32eSJiri Olsa { 288cd82a32eSJiri Olsa struct perf_pmu__format *format; 289cd82a32eSJiri Olsa 290cd82a32eSJiri Olsa list_for_each_entry(format, formats, list) 291cd82a32eSJiri Olsa if (!strcmp(format->name, name)) 292cd82a32eSJiri Olsa return format; 293cd82a32eSJiri Olsa 294cd82a32eSJiri Olsa return NULL; 295cd82a32eSJiri Olsa } 296cd82a32eSJiri Olsa 297cd82a32eSJiri Olsa /* 298cd82a32eSJiri Olsa * Returns value based on the format definition (format parameter) 299cd82a32eSJiri Olsa * and unformated value (value parameter). 300cd82a32eSJiri Olsa * 301cd82a32eSJiri Olsa * TODO maybe optimize a little ;) 302cd82a32eSJiri Olsa */ 303cd82a32eSJiri Olsa static __u64 pmu_format_value(unsigned long *format, __u64 value) 304cd82a32eSJiri Olsa { 305cd82a32eSJiri Olsa unsigned long fbit, vbit; 306cd82a32eSJiri Olsa __u64 v = 0; 307cd82a32eSJiri Olsa 308cd82a32eSJiri Olsa for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 309cd82a32eSJiri Olsa 310cd82a32eSJiri Olsa if (!test_bit(fbit, format)) 311cd82a32eSJiri Olsa continue; 312cd82a32eSJiri Olsa 313cd82a32eSJiri Olsa if (!(value & (1llu << vbit++))) 314cd82a32eSJiri Olsa continue; 315cd82a32eSJiri Olsa 316cd82a32eSJiri Olsa v |= (1llu << fbit); 317cd82a32eSJiri Olsa } 318cd82a32eSJiri Olsa 319cd82a32eSJiri Olsa return v; 320cd82a32eSJiri Olsa } 321cd82a32eSJiri Olsa 322cd82a32eSJiri Olsa /* 323cd82a32eSJiri Olsa * Setup one of config[12] attr members based on the 324cd82a32eSJiri Olsa * user input data - temr parameter. 325cd82a32eSJiri Olsa */ 326cd82a32eSJiri Olsa static int pmu_config_term(struct list_head *formats, 327cd82a32eSJiri Olsa struct perf_event_attr *attr, 328cd82a32eSJiri Olsa struct parse_events__term *term) 329cd82a32eSJiri Olsa { 330cd82a32eSJiri Olsa struct perf_pmu__format *format; 331cd82a32eSJiri Olsa __u64 *vp; 332cd82a32eSJiri Olsa 333cd82a32eSJiri Olsa /* 334cd82a32eSJiri Olsa * Support only for hardcoded and numnerial terms. 335cd82a32eSJiri Olsa * Hardcoded terms should be already in, so nothing 336cd82a32eSJiri Olsa * to be done for them. 337cd82a32eSJiri Olsa */ 338cd82a32eSJiri Olsa if (parse_events__is_hardcoded_term(term)) 339cd82a32eSJiri Olsa return 0; 340cd82a32eSJiri Olsa 34116fa7e82SJiri Olsa if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) 342cd82a32eSJiri Olsa return -EINVAL; 343cd82a32eSJiri Olsa 344cd82a32eSJiri Olsa format = pmu_find_format(formats, term->config); 345cd82a32eSJiri Olsa if (!format) 346cd82a32eSJiri Olsa return -EINVAL; 347cd82a32eSJiri Olsa 348cd82a32eSJiri Olsa switch (format->value) { 349cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG: 350cd82a32eSJiri Olsa vp = &attr->config; 351cd82a32eSJiri Olsa break; 352cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG1: 353cd82a32eSJiri Olsa vp = &attr->config1; 354cd82a32eSJiri Olsa break; 355cd82a32eSJiri Olsa case PERF_PMU_FORMAT_VALUE_CONFIG2: 356cd82a32eSJiri Olsa vp = &attr->config2; 357cd82a32eSJiri Olsa break; 358cd82a32eSJiri Olsa default: 359cd82a32eSJiri Olsa return -EINVAL; 360cd82a32eSJiri Olsa } 361cd82a32eSJiri Olsa 36216fa7e82SJiri Olsa /* 36316fa7e82SJiri Olsa * XXX If we ever decide to go with string values for 36416fa7e82SJiri Olsa * non-hardcoded terms, here's the place to translate 36516fa7e82SJiri Olsa * them into value. 36616fa7e82SJiri Olsa */ 367cd82a32eSJiri Olsa *vp |= pmu_format_value(format->bits, term->val.num); 368cd82a32eSJiri Olsa return 0; 369cd82a32eSJiri Olsa } 370cd82a32eSJiri Olsa 371cd82a32eSJiri Olsa static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 372cd82a32eSJiri Olsa struct list_head *head_terms) 373cd82a32eSJiri Olsa { 3746b5fc39bSJiri Olsa struct parse_events__term *term; 375cd82a32eSJiri Olsa 3766b5fc39bSJiri Olsa list_for_each_entry(term, head_terms, list) 377cd82a32eSJiri Olsa if (pmu_config_term(formats, attr, term)) 378cd82a32eSJiri Olsa return -EINVAL; 379cd82a32eSJiri Olsa 380cd82a32eSJiri Olsa return 0; 381cd82a32eSJiri Olsa } 382cd82a32eSJiri Olsa 383cd82a32eSJiri Olsa /* 384cd82a32eSJiri Olsa * Configures event's 'attr' parameter based on the: 385cd82a32eSJiri Olsa * 1) users input - specified in terms parameter 386cd82a32eSJiri Olsa * 2) pmu format definitions - specified by pmu parameter 387cd82a32eSJiri Olsa */ 388cd82a32eSJiri Olsa int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 389cd82a32eSJiri Olsa struct list_head *head_terms) 390cd82a32eSJiri Olsa { 391cd82a32eSJiri Olsa attr->type = pmu->type; 392cd82a32eSJiri Olsa return pmu_config(&pmu->format, attr, head_terms); 393cd82a32eSJiri Olsa } 394cd82a32eSJiri Olsa 395a6146d50SZheng Yan static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 396a6146d50SZheng Yan struct parse_events__term *term) 397a6146d50SZheng Yan { 398a6146d50SZheng Yan struct perf_pmu__alias *alias; 399a6146d50SZheng Yan char *name; 400a6146d50SZheng Yan 401a6146d50SZheng Yan if (parse_events__is_hardcoded_term(term)) 402a6146d50SZheng Yan return NULL; 403a6146d50SZheng Yan 404a6146d50SZheng Yan if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { 405a6146d50SZheng Yan if (term->val.num != 1) 406a6146d50SZheng Yan return NULL; 407a6146d50SZheng Yan if (pmu_find_format(&pmu->format, term->config)) 408a6146d50SZheng Yan return NULL; 409a6146d50SZheng Yan name = term->config; 410a6146d50SZheng Yan } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { 411a6146d50SZheng Yan if (strcasecmp(term->config, "event")) 412a6146d50SZheng Yan return NULL; 413a6146d50SZheng Yan name = term->val.str; 414a6146d50SZheng Yan } else { 415a6146d50SZheng Yan return NULL; 416a6146d50SZheng Yan } 417a6146d50SZheng Yan 418a6146d50SZheng Yan list_for_each_entry(alias, &pmu->aliases, list) { 419a6146d50SZheng Yan if (!strcasecmp(alias->name, name)) 420a6146d50SZheng Yan return alias; 421a6146d50SZheng Yan } 422a6146d50SZheng Yan return NULL; 423a6146d50SZheng Yan } 424a6146d50SZheng Yan 425a6146d50SZheng Yan /* 426a6146d50SZheng Yan * Find alias in the terms list and replace it with the terms 427a6146d50SZheng Yan * defined for the alias 428a6146d50SZheng Yan */ 429a6146d50SZheng Yan int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 430a6146d50SZheng Yan { 431a6146d50SZheng Yan struct parse_events__term *term, *h; 432a6146d50SZheng Yan struct perf_pmu__alias *alias; 433a6146d50SZheng Yan int ret; 434a6146d50SZheng Yan 435a6146d50SZheng Yan list_for_each_entry_safe(term, h, head_terms, list) { 436a6146d50SZheng Yan alias = pmu_find_alias(pmu, term); 437a6146d50SZheng Yan if (!alias) 438a6146d50SZheng Yan continue; 439a6146d50SZheng Yan ret = pmu_alias_terms(alias, &term->list); 440a6146d50SZheng Yan if (ret) 441a6146d50SZheng Yan return ret; 442a6146d50SZheng Yan list_del(&term->list); 443a6146d50SZheng Yan free(term); 444a6146d50SZheng Yan } 445a6146d50SZheng Yan return 0; 446a6146d50SZheng Yan } 447a6146d50SZheng Yan 448cd82a32eSJiri Olsa int perf_pmu__new_format(struct list_head *list, char *name, 449cd82a32eSJiri Olsa int config, unsigned long *bits) 450cd82a32eSJiri Olsa { 451cd82a32eSJiri Olsa struct perf_pmu__format *format; 452cd82a32eSJiri Olsa 453cd82a32eSJiri Olsa format = zalloc(sizeof(*format)); 454cd82a32eSJiri Olsa if (!format) 455cd82a32eSJiri Olsa return -ENOMEM; 456cd82a32eSJiri Olsa 457cd82a32eSJiri Olsa format->name = strdup(name); 458cd82a32eSJiri Olsa format->value = config; 459cd82a32eSJiri Olsa memcpy(format->bits, bits, sizeof(format->bits)); 460cd82a32eSJiri Olsa 461cd82a32eSJiri Olsa list_add_tail(&format->list, list); 462cd82a32eSJiri Olsa return 0; 463cd82a32eSJiri Olsa } 464cd82a32eSJiri Olsa 465cd82a32eSJiri Olsa void perf_pmu__set_format(unsigned long *bits, long from, long to) 466cd82a32eSJiri Olsa { 467cd82a32eSJiri Olsa long b; 468cd82a32eSJiri Olsa 469cd82a32eSJiri Olsa if (!to) 470cd82a32eSJiri Olsa to = from; 471cd82a32eSJiri Olsa 472cd82a32eSJiri Olsa memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); 473cd82a32eSJiri Olsa for (b = from; b <= to; b++) 474cd82a32eSJiri Olsa set_bit(b, bits); 475cd82a32eSJiri Olsa } 476cd82a32eSJiri Olsa 477cd82a32eSJiri Olsa /* Simulated format definitions. */ 478cd82a32eSJiri Olsa static struct test_format { 479cd82a32eSJiri Olsa const char *name; 480cd82a32eSJiri Olsa const char *value; 481cd82a32eSJiri Olsa } test_formats[] = { 482cd82a32eSJiri Olsa { "krava01", "config:0-1,62-63\n", }, 483cd82a32eSJiri Olsa { "krava02", "config:10-17\n", }, 484cd82a32eSJiri Olsa { "krava03", "config:5\n", }, 485cd82a32eSJiri Olsa { "krava11", "config1:0,2,4,6,8,20-28\n", }, 486cd82a32eSJiri Olsa { "krava12", "config1:63\n", }, 487cd82a32eSJiri Olsa { "krava13", "config1:45-47\n", }, 488cd82a32eSJiri Olsa { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", }, 489cd82a32eSJiri Olsa { "krava22", "config2:8,18,48,58\n", }, 490cd82a32eSJiri Olsa { "krava23", "config2:28-29,38\n", }, 491cd82a32eSJiri Olsa }; 492cd82a32eSJiri Olsa 493cd82a32eSJiri Olsa #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format)) 494cd82a32eSJiri Olsa 495cd82a32eSJiri Olsa /* Simulated users input. */ 496cd82a32eSJiri Olsa static struct parse_events__term test_terms[] = { 497cd82a32eSJiri Olsa { 498cd82a32eSJiri Olsa .config = (char *) "krava01", 499cd82a32eSJiri Olsa .val.num = 15, 50016fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 50116fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 502cd82a32eSJiri Olsa }, 503cd82a32eSJiri Olsa { 504cd82a32eSJiri Olsa .config = (char *) "krava02", 505cd82a32eSJiri Olsa .val.num = 170, 50616fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 50716fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 508cd82a32eSJiri Olsa }, 509cd82a32eSJiri Olsa { 510cd82a32eSJiri Olsa .config = (char *) "krava03", 511cd82a32eSJiri Olsa .val.num = 1, 51216fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 51316fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 514cd82a32eSJiri Olsa }, 515cd82a32eSJiri Olsa { 516cd82a32eSJiri Olsa .config = (char *) "krava11", 517cd82a32eSJiri Olsa .val.num = 27, 51816fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 51916fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 520cd82a32eSJiri Olsa }, 521cd82a32eSJiri Olsa { 522cd82a32eSJiri Olsa .config = (char *) "krava12", 523cd82a32eSJiri Olsa .val.num = 1, 52416fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 52516fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 526cd82a32eSJiri Olsa }, 527cd82a32eSJiri Olsa { 528cd82a32eSJiri Olsa .config = (char *) "krava13", 529cd82a32eSJiri Olsa .val.num = 2, 53016fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 53116fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 532cd82a32eSJiri Olsa }, 533cd82a32eSJiri Olsa { 534cd82a32eSJiri Olsa .config = (char *) "krava21", 535cd82a32eSJiri Olsa .val.num = 119, 53616fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 53716fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 538cd82a32eSJiri Olsa }, 539cd82a32eSJiri Olsa { 540cd82a32eSJiri Olsa .config = (char *) "krava22", 541cd82a32eSJiri Olsa .val.num = 11, 54216fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 54316fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 544cd82a32eSJiri Olsa }, 545cd82a32eSJiri Olsa { 546cd82a32eSJiri Olsa .config = (char *) "krava23", 547cd82a32eSJiri Olsa .val.num = 2, 54816fa7e82SJiri Olsa .type_val = PARSE_EVENTS__TERM_TYPE_NUM, 54916fa7e82SJiri Olsa .type_term = PARSE_EVENTS__TERM_TYPE_USER, 550cd82a32eSJiri Olsa }, 551cd82a32eSJiri Olsa }; 552cd82a32eSJiri Olsa #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) 553cd82a32eSJiri Olsa 554cd82a32eSJiri Olsa /* 555cd82a32eSJiri Olsa * Prepare format directory data, exported by kernel 556cd82a32eSJiri Olsa * at /sys/bus/event_source/devices/<dev>/format. 557cd82a32eSJiri Olsa */ 558cd82a32eSJiri Olsa static char *test_format_dir_get(void) 559cd82a32eSJiri Olsa { 560cd82a32eSJiri Olsa static char dir[PATH_MAX]; 561cd82a32eSJiri Olsa unsigned int i; 562cd82a32eSJiri Olsa 563cd82a32eSJiri Olsa snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX"); 564cd82a32eSJiri Olsa if (!mkdtemp(dir)) 565cd82a32eSJiri Olsa return NULL; 566cd82a32eSJiri Olsa 567cd82a32eSJiri Olsa for (i = 0; i < TEST_FORMATS_CNT; i++) { 568cd82a32eSJiri Olsa static char name[PATH_MAX]; 569cd82a32eSJiri Olsa struct test_format *format = &test_formats[i]; 570cd82a32eSJiri Olsa FILE *file; 571cd82a32eSJiri Olsa 572cd82a32eSJiri Olsa snprintf(name, PATH_MAX, "%s/%s", dir, format->name); 573cd82a32eSJiri Olsa 574cd82a32eSJiri Olsa file = fopen(name, "w"); 575cd82a32eSJiri Olsa if (!file) 576cd82a32eSJiri Olsa return NULL; 577cd82a32eSJiri Olsa 578cd82a32eSJiri Olsa if (1 != fwrite(format->value, strlen(format->value), 1, file)) 579cd82a32eSJiri Olsa break; 580cd82a32eSJiri Olsa 581cd82a32eSJiri Olsa fclose(file); 582cd82a32eSJiri Olsa } 583cd82a32eSJiri Olsa 584cd82a32eSJiri Olsa return dir; 585cd82a32eSJiri Olsa } 586cd82a32eSJiri Olsa 587cd82a32eSJiri Olsa /* Cleanup format directory. */ 588cd82a32eSJiri Olsa static int test_format_dir_put(char *dir) 589cd82a32eSJiri Olsa { 590cd82a32eSJiri Olsa char buf[PATH_MAX]; 591cd82a32eSJiri Olsa snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir); 592cd82a32eSJiri Olsa if (system(buf)) 593cd82a32eSJiri Olsa return -1; 594cd82a32eSJiri Olsa 595cd82a32eSJiri Olsa snprintf(buf, PATH_MAX, "rmdir %s\n", dir); 596cd82a32eSJiri Olsa return system(buf); 597cd82a32eSJiri Olsa } 598cd82a32eSJiri Olsa 599cd82a32eSJiri Olsa static struct list_head *test_terms_list(void) 600cd82a32eSJiri Olsa { 601cd82a32eSJiri Olsa static LIST_HEAD(terms); 602cd82a32eSJiri Olsa unsigned int i; 603cd82a32eSJiri Olsa 604cd82a32eSJiri Olsa for (i = 0; i < TERMS_CNT; i++) 605cd82a32eSJiri Olsa list_add_tail(&test_terms[i].list, &terms); 606cd82a32eSJiri Olsa 607cd82a32eSJiri Olsa return &terms; 608cd82a32eSJiri Olsa } 609cd82a32eSJiri Olsa 610cd82a32eSJiri Olsa #undef TERMS_CNT 611cd82a32eSJiri Olsa 612cd82a32eSJiri Olsa int perf_pmu__test(void) 613cd82a32eSJiri Olsa { 614cd82a32eSJiri Olsa char *format = test_format_dir_get(); 615cd82a32eSJiri Olsa LIST_HEAD(formats); 616cd82a32eSJiri Olsa struct list_head *terms = test_terms_list(); 617cd82a32eSJiri Olsa int ret; 618cd82a32eSJiri Olsa 619cd82a32eSJiri Olsa if (!format) 620cd82a32eSJiri Olsa return -EINVAL; 621cd82a32eSJiri Olsa 622cd82a32eSJiri Olsa do { 623cd82a32eSJiri Olsa struct perf_event_attr attr; 624cd82a32eSJiri Olsa 625cd82a32eSJiri Olsa memset(&attr, 0, sizeof(attr)); 626cd82a32eSJiri Olsa 627cd82a32eSJiri Olsa ret = pmu_format_parse(format, &formats); 628cd82a32eSJiri Olsa if (ret) 629cd82a32eSJiri Olsa break; 630cd82a32eSJiri Olsa 631cd82a32eSJiri Olsa ret = pmu_config(&formats, &attr, terms); 632cd82a32eSJiri Olsa if (ret) 633cd82a32eSJiri Olsa break; 634cd82a32eSJiri Olsa 635cd82a32eSJiri Olsa ret = -EINVAL; 636cd82a32eSJiri Olsa 637cd82a32eSJiri Olsa if (attr.config != 0xc00000000002a823) 638cd82a32eSJiri Olsa break; 639cd82a32eSJiri Olsa if (attr.config1 != 0x8000400000000145) 640cd82a32eSJiri Olsa break; 641cd82a32eSJiri Olsa if (attr.config2 != 0x0400000020041d07) 642cd82a32eSJiri Olsa break; 643cd82a32eSJiri Olsa 644cd82a32eSJiri Olsa ret = 0; 645cd82a32eSJiri Olsa } while (0); 646cd82a32eSJiri Olsa 647cd82a32eSJiri Olsa test_format_dir_put(format); 648cd82a32eSJiri Olsa return ret; 649cd82a32eSJiri Olsa } 650