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