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