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