.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | #include <linux/hw_breakpoint.h> |
---|
3 | 3 | #include <linux/err.h> |
---|
| 4 | +#include <linux/zalloc.h> |
---|
4 | 5 | #include <dirent.h> |
---|
5 | 6 | #include <errno.h> |
---|
6 | 7 | #include <sys/ioctl.h> |
---|
.. | .. |
---|
9 | 10 | #include <fcntl.h> |
---|
10 | 11 | #include <sys/param.h> |
---|
11 | 12 | #include "term.h" |
---|
12 | | -#include "../perf.h" |
---|
| 13 | +#include "build-id.h" |
---|
13 | 14 | #include "evlist.h" |
---|
14 | 15 | #include "evsel.h" |
---|
| 16 | +#include <subcmd/pager.h> |
---|
15 | 17 | #include <subcmd/parse-options.h> |
---|
16 | 18 | #include "parse-events.h" |
---|
17 | 19 | #include <subcmd/exec-cmd.h> |
---|
18 | 20 | #include "string2.h" |
---|
19 | 21 | #include "strlist.h" |
---|
20 | 22 | #include "symbol.h" |
---|
21 | | -#include "cache.h" |
---|
22 | 23 | #include "header.h" |
---|
23 | 24 | #include "bpf-loader.h" |
---|
24 | 25 | #include "debug.h" |
---|
25 | 26 | #include <api/fs/tracing_path.h> |
---|
| 27 | +#include <perf/cpumap.h> |
---|
26 | 28 | #include "parse-events-bison.h" |
---|
27 | | -#define YY_EXTRA_TYPE int |
---|
| 29 | +#define YY_EXTRA_TYPE void* |
---|
28 | 30 | #include "parse-events-flex.h" |
---|
29 | 31 | #include "pmu.h" |
---|
30 | 32 | #include "thread_map.h" |
---|
31 | | -#include "cpumap.h" |
---|
32 | 33 | #include "probe-file.h" |
---|
33 | 34 | #include "asm/bug.h" |
---|
34 | 35 | #include "util/parse-branch-options.h" |
---|
35 | 36 | #include "metricgroup.h" |
---|
| 37 | +#include "util/evsel_config.h" |
---|
| 38 | +#include "util/event.h" |
---|
| 39 | +#include "util/pfm.h" |
---|
| 40 | +#include "perf.h" |
---|
36 | 41 | |
---|
37 | 42 | #define MAX_NAME_LEN 100 |
---|
38 | 43 | |
---|
.. | .. |
---|
179 | 184 | |
---|
180 | 185 | #define MAX_EVENT_LENGTH 512 |
---|
181 | 186 | |
---|
| 187 | +void parse_events__handle_error(struct parse_events_error *err, int idx, |
---|
| 188 | + char *str, char *help) |
---|
| 189 | +{ |
---|
| 190 | + if (WARN(!str, "WARNING: failed to provide error string\n")) { |
---|
| 191 | + free(help); |
---|
| 192 | + return; |
---|
| 193 | + } |
---|
| 194 | + switch (err->num_errors) { |
---|
| 195 | + case 0: |
---|
| 196 | + err->idx = idx; |
---|
| 197 | + err->str = str; |
---|
| 198 | + err->help = help; |
---|
| 199 | + break; |
---|
| 200 | + case 1: |
---|
| 201 | + err->first_idx = err->idx; |
---|
| 202 | + err->idx = idx; |
---|
| 203 | + err->first_str = err->str; |
---|
| 204 | + err->str = str; |
---|
| 205 | + err->first_help = err->help; |
---|
| 206 | + err->help = help; |
---|
| 207 | + break; |
---|
| 208 | + default: |
---|
| 209 | + pr_debug("Multiple errors dropping message: %s (%s)\n", |
---|
| 210 | + err->str, err->help); |
---|
| 211 | + free(err->str); |
---|
| 212 | + err->str = str; |
---|
| 213 | + free(err->help); |
---|
| 214 | + err->help = help; |
---|
| 215 | + break; |
---|
| 216 | + } |
---|
| 217 | + err->num_errors++; |
---|
| 218 | +} |
---|
182 | 219 | |
---|
183 | 220 | struct tracepoint_path *tracepoint_id_to_path(u64 config) |
---|
184 | 221 | { |
---|
.. | .. |
---|
307 | 344 | return NULL; |
---|
308 | 345 | } |
---|
309 | 346 | |
---|
310 | | -static struct perf_evsel * |
---|
| 347 | +static struct evsel * |
---|
311 | 348 | __add_event(struct list_head *list, int *idx, |
---|
312 | 349 | struct perf_event_attr *attr, |
---|
| 350 | + bool init_attr, |
---|
313 | 351 | char *name, struct perf_pmu *pmu, |
---|
314 | | - struct list_head *config_terms, bool auto_merge_stats) |
---|
| 352 | + struct list_head *config_terms, bool auto_merge_stats, |
---|
| 353 | + const char *cpu_list) |
---|
315 | 354 | { |
---|
316 | | - struct perf_evsel *evsel; |
---|
317 | | - struct cpu_map *cpus = pmu ? pmu->cpus : NULL; |
---|
| 355 | + struct evsel *evsel; |
---|
| 356 | + struct perf_cpu_map *cpus = pmu ? perf_cpu_map__get(pmu->cpus) : |
---|
| 357 | + cpu_list ? perf_cpu_map__new(cpu_list) : NULL; |
---|
318 | 358 | |
---|
319 | | - event_attr_init(attr); |
---|
| 359 | + if (pmu) |
---|
| 360 | + perf_pmu__warn_invalid_formats(pmu); |
---|
320 | 361 | |
---|
321 | | - evsel = perf_evsel__new_idx(attr, *idx); |
---|
322 | | - if (!evsel) |
---|
| 362 | + if (pmu && attr->type == PERF_TYPE_RAW) |
---|
| 363 | + perf_pmu__warn_invalid_config(pmu, attr->config, name); |
---|
| 364 | + |
---|
| 365 | + if (init_attr) |
---|
| 366 | + event_attr_init(attr); |
---|
| 367 | + |
---|
| 368 | + evsel = evsel__new_idx(attr, *idx); |
---|
| 369 | + if (!evsel) { |
---|
| 370 | + perf_cpu_map__put(cpus); |
---|
323 | 371 | return NULL; |
---|
| 372 | + } |
---|
324 | 373 | |
---|
325 | 374 | (*idx)++; |
---|
326 | | - evsel->cpus = cpu_map__get(cpus); |
---|
327 | | - evsel->own_cpus = cpu_map__get(cpus); |
---|
328 | | - evsel->system_wide = pmu ? pmu->is_uncore : false; |
---|
| 375 | + evsel->core.cpus = cpus; |
---|
| 376 | + evsel->core.own_cpus = perf_cpu_map__get(cpus); |
---|
| 377 | + evsel->core.system_wide = pmu ? pmu->is_uncore : false; |
---|
329 | 378 | evsel->auto_merge_stats = auto_merge_stats; |
---|
330 | 379 | |
---|
331 | 380 | if (name) |
---|
.. | .. |
---|
334 | 383 | if (config_terms) |
---|
335 | 384 | list_splice(config_terms, &evsel->config_terms); |
---|
336 | 385 | |
---|
337 | | - list_add_tail(&evsel->node, list); |
---|
| 386 | + if (list) |
---|
| 387 | + list_add_tail(&evsel->core.node, list); |
---|
| 388 | + |
---|
338 | 389 | return evsel; |
---|
| 390 | +} |
---|
| 391 | + |
---|
| 392 | +struct evsel *parse_events__add_event(int idx, struct perf_event_attr *attr, |
---|
| 393 | + char *name, struct perf_pmu *pmu) |
---|
| 394 | +{ |
---|
| 395 | + return __add_event(NULL, &idx, attr, false, name, pmu, NULL, false, |
---|
| 396 | + NULL); |
---|
339 | 397 | } |
---|
340 | 398 | |
---|
341 | 399 | static int add_event(struct list_head *list, int *idx, |
---|
342 | 400 | struct perf_event_attr *attr, char *name, |
---|
343 | 401 | struct list_head *config_terms) |
---|
344 | 402 | { |
---|
345 | | - return __add_event(list, idx, attr, name, NULL, config_terms, false) ? 0 : -ENOMEM; |
---|
| 403 | + return __add_event(list, idx, attr, true, name, NULL, config_terms, |
---|
| 404 | + false, NULL) ? 0 : -ENOMEM; |
---|
346 | 405 | } |
---|
347 | 406 | |
---|
348 | | -static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
---|
| 407 | +static int add_event_tool(struct list_head *list, int *idx, |
---|
| 408 | + enum perf_tool_event tool_event) |
---|
| 409 | +{ |
---|
| 410 | + struct evsel *evsel; |
---|
| 411 | + struct perf_event_attr attr = { |
---|
| 412 | + .type = PERF_TYPE_SOFTWARE, |
---|
| 413 | + .config = PERF_COUNT_SW_DUMMY, |
---|
| 414 | + }; |
---|
| 415 | + |
---|
| 416 | + evsel = __add_event(list, idx, &attr, true, NULL, NULL, NULL, false, |
---|
| 417 | + "0"); |
---|
| 418 | + if (!evsel) |
---|
| 419 | + return -ENOMEM; |
---|
| 420 | + evsel->tool_event = tool_event; |
---|
| 421 | + if (tool_event == PERF_TOOL_DURATION_TIME) |
---|
| 422 | + evsel->unit = "ns"; |
---|
| 423 | + return 0; |
---|
| 424 | +} |
---|
| 425 | + |
---|
| 426 | +static int parse_aliases(char *str, const char *names[][EVSEL__MAX_ALIASES], int size) |
---|
349 | 427 | { |
---|
350 | 428 | int i, j; |
---|
351 | 429 | int n, longest = -1; |
---|
352 | 430 | |
---|
353 | 431 | for (i = 0; i < size; i++) { |
---|
354 | | - for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) { |
---|
| 432 | + for (j = 0; j < EVSEL__MAX_ALIASES && names[i][j]; j++) { |
---|
355 | 433 | n = strlen(names[i][j]); |
---|
356 | 434 | if (n > longest && !strncasecmp(str, names[i][j], n)) |
---|
357 | 435 | longest = n; |
---|
.. | .. |
---|
390 | 468 | * No fallback - if we cannot get a clear cache type |
---|
391 | 469 | * then bail out: |
---|
392 | 470 | */ |
---|
393 | | - cache_type = parse_aliases(type, perf_evsel__hw_cache, |
---|
394 | | - PERF_COUNT_HW_CACHE_MAX); |
---|
| 471 | + cache_type = parse_aliases(type, evsel__hw_cache, PERF_COUNT_HW_CACHE_MAX); |
---|
395 | 472 | if (cache_type == -1) |
---|
396 | 473 | return -EINVAL; |
---|
397 | 474 | |
---|
.. | .. |
---|
404 | 481 | n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); |
---|
405 | 482 | |
---|
406 | 483 | if (cache_op == -1) { |
---|
407 | | - cache_op = parse_aliases(str, perf_evsel__hw_cache_op, |
---|
| 484 | + cache_op = parse_aliases(str, evsel__hw_cache_op, |
---|
408 | 485 | PERF_COUNT_HW_CACHE_OP_MAX); |
---|
409 | 486 | if (cache_op >= 0) { |
---|
410 | | - if (!perf_evsel__is_cache_op_valid(cache_type, cache_op)) |
---|
| 487 | + if (!evsel__is_cache_op_valid(cache_type, cache_op)) |
---|
411 | 488 | return -EINVAL; |
---|
412 | 489 | continue; |
---|
413 | 490 | } |
---|
414 | 491 | } |
---|
415 | 492 | |
---|
416 | 493 | if (cache_result == -1) { |
---|
417 | | - cache_result = parse_aliases(str, perf_evsel__hw_cache_result, |
---|
| 494 | + cache_result = parse_aliases(str, evsel__hw_cache_result, |
---|
418 | 495 | PERF_COUNT_HW_CACHE_RESULT_MAX); |
---|
419 | 496 | if (cache_result >= 0) |
---|
420 | 497 | continue; |
---|
.. | .. |
---|
451 | 528 | static void tracepoint_error(struct parse_events_error *e, int err, |
---|
452 | 529 | const char *sys, const char *name) |
---|
453 | 530 | { |
---|
| 531 | + const char *str; |
---|
454 | 532 | char help[BUFSIZ]; |
---|
455 | 533 | |
---|
456 | 534 | if (!e) |
---|
.. | .. |
---|
464 | 542 | |
---|
465 | 543 | switch (err) { |
---|
466 | 544 | case EACCES: |
---|
467 | | - e->str = strdup("can't access trace events"); |
---|
| 545 | + str = "can't access trace events"; |
---|
468 | 546 | break; |
---|
469 | 547 | case ENOENT: |
---|
470 | | - e->str = strdup("unknown tracepoint"); |
---|
| 548 | + str = "unknown tracepoint"; |
---|
471 | 549 | break; |
---|
472 | 550 | default: |
---|
473 | | - e->str = strdup("failed to add tracepoint"); |
---|
| 551 | + str = "failed to add tracepoint"; |
---|
474 | 552 | break; |
---|
475 | 553 | } |
---|
476 | 554 | |
---|
477 | 555 | tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); |
---|
478 | | - e->help = strdup(help); |
---|
| 556 | + parse_events__handle_error(e, 0, strdup(str), strdup(help)); |
---|
479 | 557 | } |
---|
480 | 558 | |
---|
481 | 559 | static int add_tracepoint(struct list_head *list, int *idx, |
---|
.. | .. |
---|
483 | 561 | struct parse_events_error *err, |
---|
484 | 562 | struct list_head *head_config) |
---|
485 | 563 | { |
---|
486 | | - struct perf_evsel *evsel; |
---|
| 564 | + struct evsel *evsel = evsel__newtp_idx(sys_name, evt_name, (*idx)++); |
---|
487 | 565 | |
---|
488 | | - evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); |
---|
489 | 566 | if (IS_ERR(evsel)) { |
---|
490 | 567 | tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name); |
---|
491 | 568 | return PTR_ERR(evsel); |
---|
.. | .. |
---|
499 | 576 | list_splice(&config_terms, &evsel->config_terms); |
---|
500 | 577 | } |
---|
501 | 578 | |
---|
502 | | - list_add_tail(&evsel->node, list); |
---|
| 579 | + list_add_tail(&evsel->core.node, list); |
---|
503 | 580 | return 0; |
---|
504 | 581 | } |
---|
505 | 582 | |
---|
.. | .. |
---|
603 | 680 | struct list_head *head_config; |
---|
604 | 681 | }; |
---|
605 | 682 | |
---|
606 | | -static int add_bpf_event(const char *group, const char *event, int fd, |
---|
| 683 | +static int add_bpf_event(const char *group, const char *event, int fd, struct bpf_object *obj, |
---|
607 | 684 | void *_param) |
---|
608 | 685 | { |
---|
609 | 686 | LIST_HEAD(new_evsels); |
---|
610 | 687 | struct __add_bpf_event_param *param = _param; |
---|
611 | 688 | struct parse_events_state *parse_state = param->parse_state; |
---|
612 | 689 | struct list_head *list = param->list; |
---|
613 | | - struct perf_evsel *pos; |
---|
| 690 | + struct evsel *pos; |
---|
614 | 691 | int err; |
---|
| 692 | + /* |
---|
| 693 | + * Check if we should add the event, i.e. if it is a TP but starts with a '!', |
---|
| 694 | + * then don't add the tracepoint, this will be used for something else, like |
---|
| 695 | + * adding to a BPF_MAP_TYPE_PROG_ARRAY. |
---|
| 696 | + * |
---|
| 697 | + * See tools/perf/examples/bpf/augmented_raw_syscalls.c |
---|
| 698 | + */ |
---|
| 699 | + if (group[0] == '!') |
---|
| 700 | + return 0; |
---|
615 | 701 | |
---|
616 | 702 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", |
---|
617 | 703 | group, event, fd); |
---|
.. | .. |
---|
620 | 706 | event, parse_state->error, |
---|
621 | 707 | param->head_config); |
---|
622 | 708 | if (err) { |
---|
623 | | - struct perf_evsel *evsel, *tmp; |
---|
| 709 | + struct evsel *evsel, *tmp; |
---|
624 | 710 | |
---|
625 | 711 | pr_debug("Failed to add BPF event %s:%s\n", |
---|
626 | 712 | group, event); |
---|
627 | | - list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { |
---|
628 | | - list_del(&evsel->node); |
---|
629 | | - perf_evsel__delete(evsel); |
---|
| 713 | + list_for_each_entry_safe(evsel, tmp, &new_evsels, core.node) { |
---|
| 714 | + list_del_init(&evsel->core.node); |
---|
| 715 | + evsel__delete(evsel); |
---|
630 | 716 | } |
---|
631 | 717 | return err; |
---|
632 | 718 | } |
---|
633 | 719 | pr_debug("adding %s:%s\n", group, event); |
---|
634 | 720 | |
---|
635 | | - list_for_each_entry(pos, &new_evsels, node) { |
---|
| 721 | + list_for_each_entry(pos, &new_evsels, core.node) { |
---|
636 | 722 | pr_debug("adding %s:%s to %p\n", |
---|
637 | 723 | group, event, pos); |
---|
638 | 724 | pos->bpf_fd = fd; |
---|
| 725 | + pos->bpf_obj = obj; |
---|
639 | 726 | } |
---|
640 | 727 | list_splice(&new_evsels, list); |
---|
641 | 728 | return 0; |
---|
.. | .. |
---|
689 | 776 | |
---|
690 | 777 | return 0; |
---|
691 | 778 | errout: |
---|
692 | | - parse_state->error->help = strdup("(add -v to see detail)"); |
---|
693 | | - parse_state->error->str = strdup(errbuf); |
---|
| 779 | + parse_events__handle_error(parse_state->error, 0, |
---|
| 780 | + strdup(errbuf), strdup("(add -v to see detail)")); |
---|
694 | 781 | return err; |
---|
695 | 782 | } |
---|
696 | 783 | |
---|
.. | .. |
---|
706 | 793 | return 0; |
---|
707 | 794 | |
---|
708 | 795 | list_for_each_entry(term, head_config, list) { |
---|
709 | | - char errbuf[BUFSIZ]; |
---|
710 | 796 | int err; |
---|
711 | 797 | |
---|
712 | 798 | if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) { |
---|
713 | | - snprintf(errbuf, sizeof(errbuf), |
---|
714 | | - "Invalid config term for BPF object"); |
---|
715 | | - errbuf[BUFSIZ - 1] = '\0'; |
---|
716 | | - |
---|
717 | | - parse_state->error->idx = term->err_term; |
---|
718 | | - parse_state->error->str = strdup(errbuf); |
---|
| 799 | + parse_events__handle_error(parse_state->error, term->err_term, |
---|
| 800 | + strdup("Invalid config term for BPF object"), |
---|
| 801 | + NULL); |
---|
719 | 802 | return -EINVAL; |
---|
720 | 803 | } |
---|
721 | 804 | |
---|
722 | 805 | err = bpf__config_obj(obj, term, parse_state->evlist, &error_pos); |
---|
723 | 806 | if (err) { |
---|
| 807 | + char errbuf[BUFSIZ]; |
---|
| 808 | + int idx; |
---|
| 809 | + |
---|
724 | 810 | bpf__strerror_config_obj(obj, term, parse_state->evlist, |
---|
725 | 811 | &error_pos, err, errbuf, |
---|
726 | 812 | sizeof(errbuf)); |
---|
727 | | - parse_state->error->help = strdup( |
---|
| 813 | + |
---|
| 814 | + if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE) |
---|
| 815 | + idx = term->err_val; |
---|
| 816 | + else |
---|
| 817 | + idx = term->err_term + error_pos; |
---|
| 818 | + |
---|
| 819 | + parse_events__handle_error(parse_state->error, idx, |
---|
| 820 | + strdup(errbuf), |
---|
| 821 | + strdup( |
---|
728 | 822 | "Hint:\tValid config terms:\n" |
---|
729 | 823 | " \tmap:[<arraymap>].value<indices>=[value]\n" |
---|
730 | 824 | " \tmap:[<eventmap>].event<indices>=[event]\n" |
---|
731 | 825 | "\n" |
---|
732 | 826 | " \twhere <indices> is something like [0,3...5] or [all]\n" |
---|
733 | | -" \t(add -v to see detail)"); |
---|
734 | | - parse_state->error->str = strdup(errbuf); |
---|
735 | | - if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE) |
---|
736 | | - parse_state->error->idx = term->err_val; |
---|
737 | | - else |
---|
738 | | - parse_state->error->idx = term->err_term + error_pos; |
---|
| 827 | +" \t(add -v to see detail)")); |
---|
739 | 828 | return err; |
---|
740 | 829 | } |
---|
741 | 830 | } |
---|
.. | .. |
---|
799 | 888 | -err, errbuf, |
---|
800 | 889 | sizeof(errbuf)); |
---|
801 | 890 | |
---|
802 | | - parse_state->error->help = strdup("(add -v to see detail)"); |
---|
803 | | - parse_state->error->str = strdup(errbuf); |
---|
| 891 | + parse_events__handle_error(parse_state->error, 0, |
---|
| 892 | + strdup(errbuf), strdup("(add -v to see detail)")); |
---|
804 | 893 | return err; |
---|
805 | 894 | } |
---|
806 | 895 | |
---|
.. | .. |
---|
859 | 948 | } |
---|
860 | 949 | |
---|
861 | 950 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
---|
862 | | - void *ptr, char *type, u64 len) |
---|
| 951 | + u64 addr, char *type, u64 len) |
---|
863 | 952 | { |
---|
864 | 953 | struct perf_event_attr attr; |
---|
865 | 954 | |
---|
866 | 955 | memset(&attr, 0, sizeof(attr)); |
---|
867 | | - attr.bp_addr = (unsigned long) ptr; |
---|
| 956 | + attr.bp_addr = addr; |
---|
868 | 957 | |
---|
869 | 958 | if (parse_breakpoint_type(type, &attr)) |
---|
870 | 959 | return -EINVAL; |
---|
.. | .. |
---|
893 | 982 | return 0; |
---|
894 | 983 | |
---|
895 | 984 | if (err) { |
---|
896 | | - err->idx = term->err_val; |
---|
897 | | - if (type == PARSE_EVENTS__TERM_TYPE_NUM) |
---|
898 | | - err->str = strdup("expected numeric value"); |
---|
899 | | - else |
---|
900 | | - err->str = strdup("expected string value"); |
---|
| 985 | + parse_events__handle_error(err, term->err_val, |
---|
| 986 | + type == PARSE_EVENTS__TERM_TYPE_NUM |
---|
| 987 | + ? strdup("expected numeric value") |
---|
| 988 | + : strdup("expected string value"), |
---|
| 989 | + NULL); |
---|
901 | 990 | } |
---|
902 | 991 | return -EINVAL; |
---|
903 | 992 | } |
---|
.. | .. |
---|
920 | 1009 | [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", |
---|
921 | 1010 | [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", |
---|
922 | 1011 | [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", |
---|
| 1012 | + [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr", |
---|
923 | 1013 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", |
---|
924 | 1014 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", |
---|
925 | 1015 | [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", |
---|
| 1016 | + [PARSE_EVENTS__TERM_TYPE_PERCORE] = "percore", |
---|
| 1017 | + [PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT] = "aux-output", |
---|
| 1018 | + [PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE] = "aux-sample-size", |
---|
926 | 1019 | }; |
---|
927 | 1020 | |
---|
928 | 1021 | static bool config_term_shrinked; |
---|
.. | .. |
---|
930 | 1023 | static bool |
---|
931 | 1024 | config_term_avail(int term_type, struct parse_events_error *err) |
---|
932 | 1025 | { |
---|
| 1026 | + char *err_str; |
---|
| 1027 | + |
---|
933 | 1028 | if (term_type < 0 || term_type >= __PARSE_EVENTS__TERM_TYPE_NR) { |
---|
934 | | - err->str = strdup("Invalid term_type"); |
---|
| 1029 | + parse_events__handle_error(err, -1, |
---|
| 1030 | + strdup("Invalid term_type"), NULL); |
---|
935 | 1031 | return false; |
---|
936 | 1032 | } |
---|
937 | 1033 | if (!config_term_shrinked) |
---|
.. | .. |
---|
943 | 1039 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: |
---|
944 | 1040 | case PARSE_EVENTS__TERM_TYPE_NAME: |
---|
945 | 1041 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
---|
| 1042 | + case PARSE_EVENTS__TERM_TYPE_PERCORE: |
---|
946 | 1043 | return true; |
---|
947 | 1044 | default: |
---|
948 | 1045 | if (!err) |
---|
949 | 1046 | return false; |
---|
950 | 1047 | |
---|
951 | 1048 | /* term_type is validated so indexing is safe */ |
---|
952 | | - if (asprintf(&err->str, "'%s' is not usable in 'perf stat'", |
---|
953 | | - config_term_names[term_type]) < 0) |
---|
954 | | - err->str = NULL; |
---|
| 1049 | + if (asprintf(&err_str, "'%s' is not usable in 'perf stat'", |
---|
| 1050 | + config_term_names[term_type]) >= 0) |
---|
| 1051 | + parse_events__handle_error(err, -1, err_str, NULL); |
---|
955 | 1052 | return false; |
---|
956 | 1053 | } |
---|
957 | 1054 | } |
---|
.. | .. |
---|
993 | 1090 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: |
---|
994 | 1091 | CHECK_TYPE_VAL(STR); |
---|
995 | 1092 | if (strcmp(term->val.str, "no") && |
---|
996 | | - parse_branch_str(term->val.str, &attr->branch_sample_type)) { |
---|
997 | | - err->str = strdup("invalid branch sample type"); |
---|
998 | | - err->idx = term->err_val; |
---|
| 1093 | + parse_branch_str(term->val.str, |
---|
| 1094 | + &attr->branch_sample_type)) { |
---|
| 1095 | + parse_events__handle_error(err, term->err_val, |
---|
| 1096 | + strdup("invalid branch sample type"), |
---|
| 1097 | + NULL); |
---|
999 | 1098 | return -EINVAL; |
---|
1000 | 1099 | } |
---|
1001 | 1100 | break; |
---|
1002 | 1101 | case PARSE_EVENTS__TERM_TYPE_TIME: |
---|
1003 | 1102 | CHECK_TYPE_VAL(NUM); |
---|
1004 | 1103 | if (term->val.num > 1) { |
---|
1005 | | - err->str = strdup("expected 0 or 1"); |
---|
1006 | | - err->idx = term->err_val; |
---|
| 1104 | + parse_events__handle_error(err, term->err_val, |
---|
| 1105 | + strdup("expected 0 or 1"), |
---|
| 1106 | + NULL); |
---|
1007 | 1107 | return -EINVAL; |
---|
1008 | 1108 | } |
---|
1009 | 1109 | break; |
---|
.. | .. |
---|
1031 | 1131 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
---|
1032 | 1132 | CHECK_TYPE_VAL(NUM); |
---|
1033 | 1133 | break; |
---|
| 1134 | + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: |
---|
| 1135 | + CHECK_TYPE_VAL(NUM); |
---|
| 1136 | + break; |
---|
| 1137 | + case PARSE_EVENTS__TERM_TYPE_PERCORE: |
---|
| 1138 | + CHECK_TYPE_VAL(NUM); |
---|
| 1139 | + if ((unsigned int)term->val.num > 1) { |
---|
| 1140 | + parse_events__handle_error(err, term->err_val, |
---|
| 1141 | + strdup("expected 0 or 1"), |
---|
| 1142 | + NULL); |
---|
| 1143 | + return -EINVAL; |
---|
| 1144 | + } |
---|
| 1145 | + break; |
---|
| 1146 | + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: |
---|
| 1147 | + CHECK_TYPE_VAL(NUM); |
---|
| 1148 | + break; |
---|
| 1149 | + case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: |
---|
| 1150 | + CHECK_TYPE_VAL(NUM); |
---|
| 1151 | + if (term->val.num > UINT_MAX) { |
---|
| 1152 | + parse_events__handle_error(err, term->err_val, |
---|
| 1153 | + strdup("too big"), |
---|
| 1154 | + NULL); |
---|
| 1155 | + return -EINVAL; |
---|
| 1156 | + } |
---|
| 1157 | + break; |
---|
1034 | 1158 | default: |
---|
1035 | | - err->str = strdup("unknown term"); |
---|
1036 | | - err->idx = term->err_term; |
---|
1037 | | - err->help = parse_events_formats_error_string(NULL); |
---|
| 1159 | + parse_events__handle_error(err, term->err_term, |
---|
| 1160 | + strdup("unknown term"), |
---|
| 1161 | + parse_events_formats_error_string(NULL)); |
---|
1038 | 1162 | return -EINVAL; |
---|
1039 | 1163 | } |
---|
1040 | 1164 | |
---|
.. | .. |
---|
1078 | 1202 | case PARSE_EVENTS__TERM_TYPE_INHERIT: |
---|
1079 | 1203 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
---|
1080 | 1204 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
---|
| 1205 | + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: |
---|
1081 | 1206 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: |
---|
1082 | 1207 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: |
---|
| 1208 | + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: |
---|
| 1209 | + case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: |
---|
1083 | 1210 | return config_term_common(attr, term, err); |
---|
1084 | 1211 | default: |
---|
1085 | 1212 | if (err) { |
---|
1086 | | - err->idx = term->err_term; |
---|
1087 | | - err->str = strdup("unknown term"); |
---|
1088 | | - err->help = strdup("valid terms: call-graph,stack-size\n"); |
---|
| 1213 | + parse_events__handle_error(err, term->err_term, |
---|
| 1214 | + strdup("unknown term"), |
---|
| 1215 | + strdup("valid terms: call-graph,stack-size\n")); |
---|
1089 | 1216 | } |
---|
1090 | 1217 | return -EINVAL; |
---|
1091 | 1218 | } |
---|
.. | .. |
---|
1110 | 1237 | static int get_config_terms(struct list_head *head_config, |
---|
1111 | 1238 | struct list_head *head_terms __maybe_unused) |
---|
1112 | 1239 | { |
---|
1113 | | -#define ADD_CONFIG_TERM(__type, __name, __val) \ |
---|
1114 | | -do { \ |
---|
1115 | | - struct perf_evsel_config_term *__t; \ |
---|
| 1240 | +#define ADD_CONFIG_TERM(__type, __weak) \ |
---|
| 1241 | + struct evsel_config_term *__t; \ |
---|
1116 | 1242 | \ |
---|
1117 | 1243 | __t = zalloc(sizeof(*__t)); \ |
---|
1118 | 1244 | if (!__t) \ |
---|
1119 | 1245 | return -ENOMEM; \ |
---|
1120 | 1246 | \ |
---|
1121 | 1247 | INIT_LIST_HEAD(&__t->list); \ |
---|
1122 | | - __t->type = PERF_EVSEL__CONFIG_TERM_ ## __type; \ |
---|
| 1248 | + __t->type = EVSEL__CONFIG_TERM_ ## __type; \ |
---|
| 1249 | + __t->weak = __weak; \ |
---|
| 1250 | + list_add_tail(&__t->list, head_terms) |
---|
| 1251 | + |
---|
| 1252 | +#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak) \ |
---|
| 1253 | +do { \ |
---|
| 1254 | + ADD_CONFIG_TERM(__type, __weak); \ |
---|
1123 | 1255 | __t->val.__name = __val; \ |
---|
1124 | | - __t->weak = term->weak; \ |
---|
1125 | | - list_add_tail(&__t->list, head_terms); \ |
---|
| 1256 | +} while (0) |
---|
| 1257 | + |
---|
| 1258 | +#define ADD_CONFIG_TERM_STR(__type, __val, __weak) \ |
---|
| 1259 | +do { \ |
---|
| 1260 | + ADD_CONFIG_TERM(__type, __weak); \ |
---|
| 1261 | + __t->val.str = strdup(__val); \ |
---|
| 1262 | + if (!__t->val.str) { \ |
---|
| 1263 | + zfree(&__t); \ |
---|
| 1264 | + return -ENOMEM; \ |
---|
| 1265 | + } \ |
---|
| 1266 | + __t->free_str = true; \ |
---|
1126 | 1267 | } while (0) |
---|
1127 | 1268 | |
---|
1128 | 1269 | struct parse_events_term *term; |
---|
.. | .. |
---|
1130 | 1271 | list_for_each_entry(term, head_config, list) { |
---|
1131 | 1272 | switch (term->type_term) { |
---|
1132 | 1273 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
---|
1133 | | - ADD_CONFIG_TERM(PERIOD, period, term->val.num); |
---|
| 1274 | + ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak); |
---|
1134 | 1275 | break; |
---|
1135 | 1276 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ: |
---|
1136 | | - ADD_CONFIG_TERM(FREQ, freq, term->val.num); |
---|
| 1277 | + ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak); |
---|
1137 | 1278 | break; |
---|
1138 | 1279 | case PARSE_EVENTS__TERM_TYPE_TIME: |
---|
1139 | | - ADD_CONFIG_TERM(TIME, time, term->val.num); |
---|
| 1280 | + ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak); |
---|
1140 | 1281 | break; |
---|
1141 | 1282 | case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: |
---|
1142 | | - ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str); |
---|
| 1283 | + ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak); |
---|
1143 | 1284 | break; |
---|
1144 | 1285 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: |
---|
1145 | | - ADD_CONFIG_TERM(BRANCH, branch, term->val.str); |
---|
| 1286 | + ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak); |
---|
1146 | 1287 | break; |
---|
1147 | 1288 | case PARSE_EVENTS__TERM_TYPE_STACKSIZE: |
---|
1148 | | - ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num); |
---|
| 1289 | + ADD_CONFIG_TERM_VAL(STACK_USER, stack_user, |
---|
| 1290 | + term->val.num, term->weak); |
---|
1149 | 1291 | break; |
---|
1150 | 1292 | case PARSE_EVENTS__TERM_TYPE_INHERIT: |
---|
1151 | | - ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 1 : 0); |
---|
| 1293 | + ADD_CONFIG_TERM_VAL(INHERIT, inherit, |
---|
| 1294 | + term->val.num ? 1 : 0, term->weak); |
---|
1152 | 1295 | break; |
---|
1153 | 1296 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
---|
1154 | | - ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1); |
---|
| 1297 | + ADD_CONFIG_TERM_VAL(INHERIT, inherit, |
---|
| 1298 | + term->val.num ? 0 : 1, term->weak); |
---|
1155 | 1299 | break; |
---|
1156 | 1300 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
---|
1157 | | - ADD_CONFIG_TERM(MAX_STACK, max_stack, term->val.num); |
---|
| 1301 | + ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack, |
---|
| 1302 | + term->val.num, term->weak); |
---|
| 1303 | + break; |
---|
| 1304 | + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: |
---|
| 1305 | + ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events, |
---|
| 1306 | + term->val.num, term->weak); |
---|
1158 | 1307 | break; |
---|
1159 | 1308 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: |
---|
1160 | | - ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 1 : 0); |
---|
| 1309 | + ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite, |
---|
| 1310 | + term->val.num ? 1 : 0, term->weak); |
---|
1161 | 1311 | break; |
---|
1162 | 1312 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: |
---|
1163 | | - ADD_CONFIG_TERM(OVERWRITE, overwrite, term->val.num ? 0 : 1); |
---|
| 1313 | + ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite, |
---|
| 1314 | + term->val.num ? 0 : 1, term->weak); |
---|
1164 | 1315 | break; |
---|
1165 | 1316 | case PARSE_EVENTS__TERM_TYPE_DRV_CFG: |
---|
1166 | | - ADD_CONFIG_TERM(DRV_CFG, drv_cfg, term->val.str); |
---|
| 1317 | + ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak); |
---|
| 1318 | + break; |
---|
| 1319 | + case PARSE_EVENTS__TERM_TYPE_PERCORE: |
---|
| 1320 | + ADD_CONFIG_TERM_VAL(PERCORE, percore, |
---|
| 1321 | + term->val.num ? true : false, term->weak); |
---|
| 1322 | + break; |
---|
| 1323 | + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: |
---|
| 1324 | + ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output, |
---|
| 1325 | + term->val.num ? 1 : 0, term->weak); |
---|
| 1326 | + break; |
---|
| 1327 | + case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: |
---|
| 1328 | + ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size, |
---|
| 1329 | + term->val.num, term->weak); |
---|
1167 | 1330 | break; |
---|
1168 | 1331 | default: |
---|
1169 | 1332 | break; |
---|
1170 | 1333 | } |
---|
1171 | 1334 | } |
---|
1172 | | -#undef ADD_EVSEL_CONFIG |
---|
| 1335 | + return 0; |
---|
| 1336 | +} |
---|
| 1337 | + |
---|
| 1338 | +/* |
---|
| 1339 | + * Add EVSEL__CONFIG_TERM_CFG_CHG where cfg_chg will have a bit set for |
---|
| 1340 | + * each bit of attr->config that the user has changed. |
---|
| 1341 | + */ |
---|
| 1342 | +static int get_config_chgs(struct perf_pmu *pmu, struct list_head *head_config, |
---|
| 1343 | + struct list_head *head_terms) |
---|
| 1344 | +{ |
---|
| 1345 | + struct parse_events_term *term; |
---|
| 1346 | + u64 bits = 0; |
---|
| 1347 | + int type; |
---|
| 1348 | + |
---|
| 1349 | + list_for_each_entry(term, head_config, list) { |
---|
| 1350 | + switch (term->type_term) { |
---|
| 1351 | + case PARSE_EVENTS__TERM_TYPE_USER: |
---|
| 1352 | + type = perf_pmu__format_type(&pmu->format, term->config); |
---|
| 1353 | + if (type != PERF_PMU_FORMAT_VALUE_CONFIG) |
---|
| 1354 | + continue; |
---|
| 1355 | + bits |= perf_pmu__format_bits(&pmu->format, term->config); |
---|
| 1356 | + break; |
---|
| 1357 | + case PARSE_EVENTS__TERM_TYPE_CONFIG: |
---|
| 1358 | + bits = ~(u64)0; |
---|
| 1359 | + break; |
---|
| 1360 | + default: |
---|
| 1361 | + break; |
---|
| 1362 | + } |
---|
| 1363 | + } |
---|
| 1364 | + |
---|
| 1365 | + if (bits) |
---|
| 1366 | + ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false); |
---|
| 1367 | + |
---|
| 1368 | +#undef ADD_CONFIG_TERM |
---|
1173 | 1369 | return 0; |
---|
1174 | 1370 | } |
---|
1175 | 1371 | |
---|
.. | .. |
---|
1219 | 1415 | get_config_name(head_config), &config_terms); |
---|
1220 | 1416 | } |
---|
1221 | 1417 | |
---|
| 1418 | +int parse_events_add_tool(struct parse_events_state *parse_state, |
---|
| 1419 | + struct list_head *list, |
---|
| 1420 | + enum perf_tool_event tool_event) |
---|
| 1421 | +{ |
---|
| 1422 | + return add_event_tool(list, &parse_state->idx, tool_event); |
---|
| 1423 | +} |
---|
| 1424 | + |
---|
| 1425 | +static bool config_term_percore(struct list_head *config_terms) |
---|
| 1426 | +{ |
---|
| 1427 | + struct evsel_config_term *term; |
---|
| 1428 | + |
---|
| 1429 | + list_for_each_entry(term, config_terms, list) { |
---|
| 1430 | + if (term->type == EVSEL__CONFIG_TERM_PERCORE) |
---|
| 1431 | + return term->val.percore; |
---|
| 1432 | + } |
---|
| 1433 | + |
---|
| 1434 | + return false; |
---|
| 1435 | +} |
---|
| 1436 | + |
---|
1222 | 1437 | int parse_events_add_pmu(struct parse_events_state *parse_state, |
---|
1223 | 1438 | struct list_head *list, char *name, |
---|
1224 | 1439 | struct list_head *head_config, |
---|
.. | .. |
---|
1228 | 1443 | struct perf_event_attr attr; |
---|
1229 | 1444 | struct perf_pmu_info info; |
---|
1230 | 1445 | struct perf_pmu *pmu; |
---|
1231 | | - struct perf_evsel *evsel; |
---|
| 1446 | + struct evsel *evsel; |
---|
1232 | 1447 | struct parse_events_error *err = parse_state->error; |
---|
1233 | 1448 | bool use_uncore_alias; |
---|
1234 | 1449 | LIST_HEAD(config_terms); |
---|
1235 | 1450 | |
---|
1236 | | - pmu = perf_pmu__find(name); |
---|
| 1451 | + pmu = parse_state->fake_pmu ?: perf_pmu__find(name); |
---|
| 1452 | + |
---|
| 1453 | + if (verbose > 1 && !(pmu && pmu->selectable)) { |
---|
| 1454 | + fprintf(stderr, "Attempting to add event pmu '%s' with '", |
---|
| 1455 | + name); |
---|
| 1456 | + if (head_config) { |
---|
| 1457 | + struct parse_events_term *term; |
---|
| 1458 | + |
---|
| 1459 | + list_for_each_entry(term, head_config, list) { |
---|
| 1460 | + fprintf(stderr, "%s,", term->config); |
---|
| 1461 | + } |
---|
| 1462 | + } |
---|
| 1463 | + fprintf(stderr, "' that may result in non-fatal errors\n"); |
---|
| 1464 | + } |
---|
| 1465 | + |
---|
1237 | 1466 | if (!pmu) { |
---|
1238 | | - if (asprintf(&err->str, |
---|
| 1467 | + char *err_str; |
---|
| 1468 | + |
---|
| 1469 | + if (asprintf(&err_str, |
---|
1239 | 1470 | "Cannot find PMU `%s'. Missing kernel support?", |
---|
1240 | | - name) < 0) |
---|
1241 | | - err->str = NULL; |
---|
| 1471 | + name) >= 0) |
---|
| 1472 | + parse_events__handle_error(err, 0, err_str, NULL); |
---|
1242 | 1473 | return -EINVAL; |
---|
1243 | 1474 | } |
---|
1244 | 1475 | |
---|
.. | .. |
---|
1253 | 1484 | |
---|
1254 | 1485 | if (!head_config) { |
---|
1255 | 1486 | attr.type = pmu->type; |
---|
1256 | | - evsel = __add_event(list, &parse_state->idx, &attr, NULL, pmu, NULL, auto_merge_stats); |
---|
| 1487 | + evsel = __add_event(list, &parse_state->idx, &attr, true, NULL, |
---|
| 1488 | + pmu, NULL, auto_merge_stats, NULL); |
---|
1257 | 1489 | if (evsel) { |
---|
1258 | 1490 | evsel->pmu_name = name ? strdup(name) : NULL; |
---|
1259 | 1491 | evsel->use_uncore_alias = use_uncore_alias; |
---|
.. | .. |
---|
1263 | 1495 | } |
---|
1264 | 1496 | } |
---|
1265 | 1497 | |
---|
1266 | | - if (perf_pmu__check_alias(pmu, head_config, &info)) |
---|
| 1498 | + if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, head_config, &info)) |
---|
1267 | 1499 | return -EINVAL; |
---|
| 1500 | + |
---|
| 1501 | + if (verbose > 1) { |
---|
| 1502 | + fprintf(stderr, "After aliases, add event pmu '%s' with '", |
---|
| 1503 | + name); |
---|
| 1504 | + if (head_config) { |
---|
| 1505 | + struct parse_events_term *term; |
---|
| 1506 | + |
---|
| 1507 | + list_for_each_entry(term, head_config, list) { |
---|
| 1508 | + fprintf(stderr, "%s,", term->config); |
---|
| 1509 | + } |
---|
| 1510 | + } |
---|
| 1511 | + fprintf(stderr, "' that may result in non-fatal errors\n"); |
---|
| 1512 | + } |
---|
1268 | 1513 | |
---|
1269 | 1514 | /* |
---|
1270 | 1515 | * Configure hardcoded terms first, no need to check |
---|
.. | .. |
---|
1276 | 1521 | if (get_config_terms(head_config, &config_terms)) |
---|
1277 | 1522 | return -ENOMEM; |
---|
1278 | 1523 | |
---|
1279 | | - if (perf_pmu__config(pmu, &attr, head_config, parse_state->error)) { |
---|
1280 | | - struct perf_evsel_config_term *pos, *tmp; |
---|
| 1524 | + /* |
---|
| 1525 | + * When using default config, record which bits of attr->config were |
---|
| 1526 | + * changed by the user. |
---|
| 1527 | + */ |
---|
| 1528 | + if (pmu->default_config && get_config_chgs(pmu, head_config, &config_terms)) |
---|
| 1529 | + return -ENOMEM; |
---|
| 1530 | + |
---|
| 1531 | + if (!parse_state->fake_pmu && perf_pmu__config(pmu, &attr, head_config, parse_state->error)) { |
---|
| 1532 | + struct evsel_config_term *pos, *tmp; |
---|
1281 | 1533 | |
---|
1282 | 1534 | list_for_each_entry_safe(pos, tmp, &config_terms, list) { |
---|
1283 | 1535 | list_del_init(&pos->list); |
---|
| 1536 | + if (pos->free_str) |
---|
| 1537 | + zfree(&pos->val.str); |
---|
1284 | 1538 | free(pos); |
---|
1285 | 1539 | } |
---|
1286 | 1540 | return -EINVAL; |
---|
1287 | 1541 | } |
---|
1288 | 1542 | |
---|
1289 | | - evsel = __add_event(list, &parse_state->idx, &attr, |
---|
| 1543 | + evsel = __add_event(list, &parse_state->idx, &attr, true, |
---|
1290 | 1544 | get_config_name(head_config), pmu, |
---|
1291 | | - &config_terms, auto_merge_stats); |
---|
1292 | | - if (evsel) { |
---|
1293 | | - evsel->unit = info.unit; |
---|
1294 | | - evsel->scale = info.scale; |
---|
1295 | | - evsel->per_pkg = info.per_pkg; |
---|
1296 | | - evsel->snapshot = info.snapshot; |
---|
1297 | | - evsel->metric_expr = info.metric_expr; |
---|
1298 | | - evsel->metric_name = info.metric_name; |
---|
1299 | | - evsel->pmu_name = name ? strdup(name) : NULL; |
---|
1300 | | - evsel->use_uncore_alias = use_uncore_alias; |
---|
1301 | | - } |
---|
| 1545 | + &config_terms, auto_merge_stats, NULL); |
---|
| 1546 | + if (!evsel) |
---|
| 1547 | + return -ENOMEM; |
---|
1302 | 1548 | |
---|
1303 | | - return evsel ? 0 : -ENOMEM; |
---|
| 1549 | + evsel->pmu_name = name ? strdup(name) : NULL; |
---|
| 1550 | + evsel->use_uncore_alias = use_uncore_alias; |
---|
| 1551 | + evsel->percore = config_term_percore(&evsel->config_terms); |
---|
| 1552 | + |
---|
| 1553 | + if (parse_state->fake_pmu) |
---|
| 1554 | + return 0; |
---|
| 1555 | + |
---|
| 1556 | + evsel->unit = info.unit; |
---|
| 1557 | + evsel->scale = info.scale; |
---|
| 1558 | + evsel->per_pkg = info.per_pkg; |
---|
| 1559 | + evsel->snapshot = info.snapshot; |
---|
| 1560 | + evsel->metric_expr = info.metric_expr; |
---|
| 1561 | + evsel->metric_name = info.metric_name; |
---|
| 1562 | + return 0; |
---|
1304 | 1563 | } |
---|
1305 | 1564 | |
---|
1306 | 1565 | int parse_events_multi_pmu_add(struct parse_events_state *parse_state, |
---|
.. | .. |
---|
1345 | 1604 | if (!parse_events_add_pmu(parse_state, list, |
---|
1346 | 1605 | pmu->name, head, |
---|
1347 | 1606 | true, true)) { |
---|
1348 | | - pr_debug("%s -> %s/%s/\n", config, |
---|
| 1607 | + pr_debug("%s -> %s/%s/\n", str, |
---|
1349 | 1608 | pmu->name, alias->str); |
---|
1350 | 1609 | ok++; |
---|
1351 | 1610 | } |
---|
.. | .. |
---|
1392 | 1651 | parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, |
---|
1393 | 1652 | struct parse_events_state *parse_state) |
---|
1394 | 1653 | { |
---|
1395 | | - struct perf_evsel *evsel, *leader; |
---|
| 1654 | + struct evsel *evsel, *leader; |
---|
1396 | 1655 | uintptr_t *leaders; |
---|
1397 | 1656 | bool is_leader = true; |
---|
1398 | 1657 | int i, nr_pmu = 0, total_members, ret = 0; |
---|
1399 | 1658 | |
---|
1400 | | - leader = list_first_entry(list, struct perf_evsel, node); |
---|
1401 | | - evsel = list_last_entry(list, struct perf_evsel, node); |
---|
| 1659 | + leader = list_first_entry(list, struct evsel, core.node); |
---|
| 1660 | + evsel = list_last_entry(list, struct evsel, core.node); |
---|
1402 | 1661 | total_members = evsel->idx - leader->idx + 1; |
---|
1403 | 1662 | |
---|
1404 | 1663 | leaders = calloc(total_members, sizeof(uintptr_t)); |
---|
.. | .. |
---|
1459 | 1718 | __evlist__for_each_entry(list, evsel) { |
---|
1460 | 1719 | if (i >= nr_pmu) |
---|
1461 | 1720 | i = 0; |
---|
1462 | | - evsel->leader = (struct perf_evsel *) leaders[i++]; |
---|
| 1721 | + evsel->leader = (struct evsel *) leaders[i++]; |
---|
1463 | 1722 | } |
---|
1464 | 1723 | |
---|
1465 | 1724 | /* The number of members and group name are same for each group */ |
---|
1466 | 1725 | for (i = 0; i < nr_pmu; i++) { |
---|
1467 | | - evsel = (struct perf_evsel *) leaders[i]; |
---|
1468 | | - evsel->nr_members = total_members / nr_pmu; |
---|
| 1726 | + evsel = (struct evsel *) leaders[i]; |
---|
| 1727 | + evsel->core.nr_members = total_members / nr_pmu; |
---|
1469 | 1728 | evsel->group_name = name ? strdup(name) : NULL; |
---|
1470 | 1729 | } |
---|
1471 | 1730 | |
---|
.. | .. |
---|
1482 | 1741 | void parse_events__set_leader(char *name, struct list_head *list, |
---|
1483 | 1742 | struct parse_events_state *parse_state) |
---|
1484 | 1743 | { |
---|
1485 | | - struct perf_evsel *leader; |
---|
| 1744 | + struct evsel *leader; |
---|
1486 | 1745 | |
---|
1487 | 1746 | if (list_empty(list)) { |
---|
1488 | 1747 | WARN_ONCE(true, "WARNING: failed to set leader: empty list"); |
---|
.. | .. |
---|
1493 | 1752 | return; |
---|
1494 | 1753 | |
---|
1495 | 1754 | __perf_evlist__set_leader(list); |
---|
1496 | | - leader = list_entry(list->next, struct perf_evsel, node); |
---|
| 1755 | + leader = list_entry(list->next, struct evsel, core.node); |
---|
1497 | 1756 | leader->group_name = name ? strdup(name) : NULL; |
---|
1498 | 1757 | } |
---|
1499 | 1758 | |
---|
.. | .. |
---|
1523 | 1782 | int sample_read; |
---|
1524 | 1783 | int pinned; |
---|
1525 | 1784 | int weak; |
---|
| 1785 | + int exclusive; |
---|
1526 | 1786 | }; |
---|
1527 | 1787 | |
---|
1528 | 1788 | static int get_event_modifier(struct event_modifier *mod, char *str, |
---|
1529 | | - struct perf_evsel *evsel) |
---|
| 1789 | + struct evsel *evsel) |
---|
1530 | 1790 | { |
---|
1531 | | - int eu = evsel ? evsel->attr.exclude_user : 0; |
---|
1532 | | - int ek = evsel ? evsel->attr.exclude_kernel : 0; |
---|
1533 | | - int eh = evsel ? evsel->attr.exclude_hv : 0; |
---|
1534 | | - int eH = evsel ? evsel->attr.exclude_host : 0; |
---|
1535 | | - int eG = evsel ? evsel->attr.exclude_guest : 0; |
---|
1536 | | - int eI = evsel ? evsel->attr.exclude_idle : 0; |
---|
1537 | | - int precise = evsel ? evsel->attr.precise_ip : 0; |
---|
| 1791 | + int eu = evsel ? evsel->core.attr.exclude_user : 0; |
---|
| 1792 | + int ek = evsel ? evsel->core.attr.exclude_kernel : 0; |
---|
| 1793 | + int eh = evsel ? evsel->core.attr.exclude_hv : 0; |
---|
| 1794 | + int eH = evsel ? evsel->core.attr.exclude_host : 0; |
---|
| 1795 | + int eG = evsel ? evsel->core.attr.exclude_guest : 0; |
---|
| 1796 | + int eI = evsel ? evsel->core.attr.exclude_idle : 0; |
---|
| 1797 | + int precise = evsel ? evsel->core.attr.precise_ip : 0; |
---|
1538 | 1798 | int precise_max = 0; |
---|
1539 | 1799 | int sample_read = 0; |
---|
1540 | | - int pinned = evsel ? evsel->attr.pinned : 0; |
---|
| 1800 | + int pinned = evsel ? evsel->core.attr.pinned : 0; |
---|
| 1801 | + int exclusive = evsel ? evsel->core.attr.exclusive : 0; |
---|
1541 | 1802 | |
---|
1542 | 1803 | int exclude = eu | ek | eh; |
---|
1543 | 1804 | int exclude_GH = evsel ? evsel->exclude_GH : 0; |
---|
.. | .. |
---|
1549 | 1810 | if (*str == 'u') { |
---|
1550 | 1811 | if (!exclude) |
---|
1551 | 1812 | exclude = eu = ek = eh = 1; |
---|
| 1813 | + if (!exclude_GH && !perf_guest) |
---|
| 1814 | + eG = 1; |
---|
1552 | 1815 | eu = 0; |
---|
1553 | 1816 | } else if (*str == 'k') { |
---|
1554 | 1817 | if (!exclude) |
---|
.. | .. |
---|
1579 | 1842 | sample_read = 1; |
---|
1580 | 1843 | } else if (*str == 'D') { |
---|
1581 | 1844 | pinned = 1; |
---|
| 1845 | + } else if (*str == 'e') { |
---|
| 1846 | + exclusive = 1; |
---|
1582 | 1847 | } else if (*str == 'W') { |
---|
1583 | 1848 | weak = 1; |
---|
1584 | 1849 | } else |
---|
.. | .. |
---|
1612 | 1877 | mod->sample_read = sample_read; |
---|
1613 | 1878 | mod->pinned = pinned; |
---|
1614 | 1879 | mod->weak = weak; |
---|
| 1880 | + mod->exclusive = exclusive; |
---|
1615 | 1881 | |
---|
1616 | 1882 | return 0; |
---|
1617 | 1883 | } |
---|
.. | .. |
---|
1625 | 1891 | char *p = str; |
---|
1626 | 1892 | |
---|
1627 | 1893 | /* The sizeof includes 0 byte as well. */ |
---|
1628 | | - if (strlen(str) > (sizeof("ukhGHpppPSDIW") - 1)) |
---|
| 1894 | + if (strlen(str) > (sizeof("ukhGHpppPSDIWe") - 1)) |
---|
1629 | 1895 | return -1; |
---|
1630 | 1896 | |
---|
1631 | 1897 | while (*p) { |
---|
.. | .. |
---|
1639 | 1905 | |
---|
1640 | 1906 | int parse_events__modifier_event(struct list_head *list, char *str, bool add) |
---|
1641 | 1907 | { |
---|
1642 | | - struct perf_evsel *evsel; |
---|
| 1908 | + struct evsel *evsel; |
---|
1643 | 1909 | struct event_modifier mod; |
---|
1644 | 1910 | |
---|
1645 | 1911 | if (str == NULL) |
---|
.. | .. |
---|
1655 | 1921 | if (add && get_event_modifier(&mod, str, evsel)) |
---|
1656 | 1922 | return -EINVAL; |
---|
1657 | 1923 | |
---|
1658 | | - evsel->attr.exclude_user = mod.eu; |
---|
1659 | | - evsel->attr.exclude_kernel = mod.ek; |
---|
1660 | | - evsel->attr.exclude_hv = mod.eh; |
---|
1661 | | - evsel->attr.precise_ip = mod.precise; |
---|
1662 | | - evsel->attr.exclude_host = mod.eH; |
---|
1663 | | - evsel->attr.exclude_guest = mod.eG; |
---|
1664 | | - evsel->attr.exclude_idle = mod.eI; |
---|
| 1924 | + evsel->core.attr.exclude_user = mod.eu; |
---|
| 1925 | + evsel->core.attr.exclude_kernel = mod.ek; |
---|
| 1926 | + evsel->core.attr.exclude_hv = mod.eh; |
---|
| 1927 | + evsel->core.attr.precise_ip = mod.precise; |
---|
| 1928 | + evsel->core.attr.exclude_host = mod.eH; |
---|
| 1929 | + evsel->core.attr.exclude_guest = mod.eG; |
---|
| 1930 | + evsel->core.attr.exclude_idle = mod.eI; |
---|
1665 | 1931 | evsel->exclude_GH = mod.exclude_GH; |
---|
1666 | 1932 | evsel->sample_read = mod.sample_read; |
---|
1667 | 1933 | evsel->precise_max = mod.precise_max; |
---|
1668 | 1934 | evsel->weak_group = mod.weak; |
---|
1669 | 1935 | |
---|
1670 | | - if (perf_evsel__is_group_leader(evsel)) |
---|
1671 | | - evsel->attr.pinned = mod.pinned; |
---|
| 1936 | + if (evsel__is_group_leader(evsel)) { |
---|
| 1937 | + evsel->core.attr.pinned = mod.pinned; |
---|
| 1938 | + evsel->core.attr.exclusive = mod.exclusive; |
---|
| 1939 | + } |
---|
1672 | 1940 | } |
---|
1673 | 1941 | |
---|
1674 | 1942 | return 0; |
---|
.. | .. |
---|
1676 | 1944 | |
---|
1677 | 1945 | int parse_events_name(struct list_head *list, char *name) |
---|
1678 | 1946 | { |
---|
1679 | | - struct perf_evsel *evsel; |
---|
| 1947 | + struct evsel *evsel; |
---|
1680 | 1948 | |
---|
1681 | 1949 | __evlist__for_each_entry(list, evsel) { |
---|
1682 | 1950 | if (!evsel->name) |
---|
.. | .. |
---|
1774 | 2042 | perf_pmu__parse_cleanup(); |
---|
1775 | 2043 | } |
---|
1776 | 2044 | |
---|
| 2045 | +/* |
---|
| 2046 | + * This function injects special term in |
---|
| 2047 | + * perf_pmu_events_list so the test code |
---|
| 2048 | + * can check on this functionality. |
---|
| 2049 | + */ |
---|
| 2050 | +int perf_pmu__test_parse_init(void) |
---|
| 2051 | +{ |
---|
| 2052 | + struct perf_pmu_event_symbol *list; |
---|
| 2053 | + |
---|
| 2054 | + list = malloc(sizeof(*list) * 1); |
---|
| 2055 | + if (!list) |
---|
| 2056 | + return -ENOMEM; |
---|
| 2057 | + |
---|
| 2058 | + list->type = PMU_EVENT_SYMBOL; |
---|
| 2059 | + list->symbol = strdup("read"); |
---|
| 2060 | + |
---|
| 2061 | + if (!list->symbol) { |
---|
| 2062 | + free(list); |
---|
| 2063 | + return -ENOMEM; |
---|
| 2064 | + } |
---|
| 2065 | + |
---|
| 2066 | + perf_pmu_events_list = list; |
---|
| 2067 | + perf_pmu_events_list_num = 1; |
---|
| 2068 | + return 0; |
---|
| 2069 | +} |
---|
| 2070 | + |
---|
1777 | 2071 | enum perf_pmu_event_symbol_type |
---|
1778 | 2072 | perf_pmu__parse_check(const char *name) |
---|
1779 | 2073 | { |
---|
.. | .. |
---|
1798 | 2092 | return r ? r->type : PMU_EVENT_SYMBOL_ERR; |
---|
1799 | 2093 | } |
---|
1800 | 2094 | |
---|
1801 | | -static int parse_events__scanner(const char *str, void *parse_state, int start_token) |
---|
| 2095 | +static int parse_events__scanner(const char *str, |
---|
| 2096 | + struct parse_events_state *parse_state) |
---|
1802 | 2097 | { |
---|
1803 | 2098 | YY_BUFFER_STATE buffer; |
---|
1804 | 2099 | void *scanner; |
---|
1805 | 2100 | int ret; |
---|
1806 | 2101 | |
---|
1807 | | - ret = parse_events_lex_init_extra(start_token, &scanner); |
---|
| 2102 | + ret = parse_events_lex_init_extra(parse_state, &scanner); |
---|
1808 | 2103 | if (ret) |
---|
1809 | 2104 | return ret; |
---|
1810 | 2105 | |
---|
.. | .. |
---|
1812 | 2107 | |
---|
1813 | 2108 | #ifdef PARSER_DEBUG |
---|
1814 | 2109 | parse_events_debug = 1; |
---|
| 2110 | + parse_events_set_debug(1, scanner); |
---|
1815 | 2111 | #endif |
---|
1816 | 2112 | ret = parse_events_parse(parse_state, scanner); |
---|
1817 | 2113 | |
---|
.. | .. |
---|
1827 | 2123 | int parse_events_terms(struct list_head *terms, const char *str) |
---|
1828 | 2124 | { |
---|
1829 | 2125 | struct parse_events_state parse_state = { |
---|
1830 | | - .terms = NULL, |
---|
| 2126 | + .terms = NULL, |
---|
| 2127 | + .stoken = PE_START_TERMS, |
---|
1831 | 2128 | }; |
---|
1832 | 2129 | int ret; |
---|
1833 | 2130 | |
---|
1834 | | - ret = parse_events__scanner(str, &parse_state, PE_START_TERMS); |
---|
| 2131 | + ret = parse_events__scanner(str, &parse_state); |
---|
| 2132 | + perf_pmu__parse_cleanup(); |
---|
| 2133 | + |
---|
1835 | 2134 | if (!ret) { |
---|
1836 | 2135 | list_splice(parse_state.terms, terms); |
---|
1837 | 2136 | zfree(&parse_state.terms); |
---|
.. | .. |
---|
1842 | 2141 | return ret; |
---|
1843 | 2142 | } |
---|
1844 | 2143 | |
---|
1845 | | -int parse_events(struct perf_evlist *evlist, const char *str, |
---|
1846 | | - struct parse_events_error *err) |
---|
| 2144 | +int __parse_events(struct evlist *evlist, const char *str, |
---|
| 2145 | + struct parse_events_error *err, struct perf_pmu *fake_pmu) |
---|
1847 | 2146 | { |
---|
1848 | 2147 | struct parse_events_state parse_state = { |
---|
1849 | | - .list = LIST_HEAD_INIT(parse_state.list), |
---|
1850 | | - .idx = evlist->nr_entries, |
---|
1851 | | - .error = err, |
---|
1852 | | - .evlist = evlist, |
---|
| 2148 | + .list = LIST_HEAD_INIT(parse_state.list), |
---|
| 2149 | + .idx = evlist->core.nr_entries, |
---|
| 2150 | + .error = err, |
---|
| 2151 | + .evlist = evlist, |
---|
| 2152 | + .stoken = PE_START_EVENTS, |
---|
| 2153 | + .fake_pmu = fake_pmu, |
---|
1853 | 2154 | }; |
---|
1854 | 2155 | int ret; |
---|
1855 | 2156 | |
---|
1856 | | - ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS); |
---|
| 2157 | + ret = parse_events__scanner(str, &parse_state); |
---|
1857 | 2158 | perf_pmu__parse_cleanup(); |
---|
1858 | 2159 | |
---|
1859 | 2160 | if (!ret && list_empty(&parse_state.list)) { |
---|
.. | .. |
---|
1867 | 2168 | perf_evlist__splice_list_tail(evlist, &parse_state.list); |
---|
1868 | 2169 | |
---|
1869 | 2170 | if (!ret) { |
---|
1870 | | - struct perf_evsel *last; |
---|
| 2171 | + struct evsel *last; |
---|
1871 | 2172 | |
---|
1872 | 2173 | evlist->nr_groups += parse_state.nr_groups; |
---|
1873 | | - last = perf_evlist__last(evlist); |
---|
| 2174 | + last = evlist__last(evlist); |
---|
1874 | 2175 | last->cmdline_group_boundary = true; |
---|
1875 | 2176 | |
---|
1876 | 2177 | return 0; |
---|
.. | .. |
---|
1878 | 2179 | |
---|
1879 | 2180 | /* |
---|
1880 | 2181 | * There are 2 users - builtin-record and builtin-test objects. |
---|
1881 | | - * Both call perf_evlist__delete in case of error, so we dont |
---|
| 2182 | + * Both call evlist__delete in case of error, so we dont |
---|
1882 | 2183 | * need to bother. |
---|
1883 | 2184 | */ |
---|
1884 | 2185 | return ret; |
---|
.. | .. |
---|
1893 | 2194 | return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col; |
---|
1894 | 2195 | } |
---|
1895 | 2196 | |
---|
1896 | | -void parse_events_print_error(struct parse_events_error *err, |
---|
1897 | | - const char *event) |
---|
| 2197 | +static void __parse_events_print_error(int err_idx, const char *err_str, |
---|
| 2198 | + const char *err_help, const char *event) |
---|
1898 | 2199 | { |
---|
1899 | 2200 | const char *str = "invalid or unsupported event: "; |
---|
1900 | 2201 | char _buf[MAX_WIDTH]; |
---|
1901 | 2202 | char *buf = (char *) event; |
---|
1902 | 2203 | int idx = 0; |
---|
1903 | | - |
---|
1904 | | - if (err->str) { |
---|
| 2204 | + if (err_str) { |
---|
1905 | 2205 | /* -2 for extra '' in the final fprintf */ |
---|
1906 | 2206 | int width = get_term_width() - 2; |
---|
1907 | 2207 | int len_event = strlen(event); |
---|
.. | .. |
---|
1924 | 2224 | buf = _buf; |
---|
1925 | 2225 | |
---|
1926 | 2226 | /* We're cutting from the beginning. */ |
---|
1927 | | - if (err->idx > max_err_idx) |
---|
1928 | | - cut = err->idx - max_err_idx; |
---|
| 2227 | + if (err_idx > max_err_idx) |
---|
| 2228 | + cut = err_idx - max_err_idx; |
---|
1929 | 2229 | |
---|
1930 | 2230 | strncpy(buf, event + cut, max_len); |
---|
1931 | 2231 | |
---|
.. | .. |
---|
1938 | 2238 | buf[max_len] = 0; |
---|
1939 | 2239 | } |
---|
1940 | 2240 | |
---|
1941 | | - idx = len_str + err->idx - cut; |
---|
| 2241 | + idx = len_str + err_idx - cut; |
---|
1942 | 2242 | } |
---|
1943 | 2243 | |
---|
1944 | 2244 | fprintf(stderr, "%s'%s'\n", str, buf); |
---|
1945 | 2245 | if (idx) { |
---|
1946 | | - fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str); |
---|
1947 | | - if (err->help) |
---|
1948 | | - fprintf(stderr, "\n%s\n", err->help); |
---|
1949 | | - zfree(&err->str); |
---|
1950 | | - zfree(&err->help); |
---|
| 2246 | + fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err_str); |
---|
| 2247 | + if (err_help) |
---|
| 2248 | + fprintf(stderr, "\n%s\n", err_help); |
---|
| 2249 | + } |
---|
| 2250 | +} |
---|
| 2251 | + |
---|
| 2252 | +void parse_events_print_error(struct parse_events_error *err, |
---|
| 2253 | + const char *event) |
---|
| 2254 | +{ |
---|
| 2255 | + if (!err->num_errors) |
---|
| 2256 | + return; |
---|
| 2257 | + |
---|
| 2258 | + __parse_events_print_error(err->idx, err->str, err->help, event); |
---|
| 2259 | + zfree(&err->str); |
---|
| 2260 | + zfree(&err->help); |
---|
| 2261 | + |
---|
| 2262 | + if (err->num_errors > 1) { |
---|
| 2263 | + fputs("\nInitial error:\n", stderr); |
---|
| 2264 | + __parse_events_print_error(err->first_idx, err->first_str, |
---|
| 2265 | + err->first_help, event); |
---|
| 2266 | + zfree(&err->first_str); |
---|
| 2267 | + zfree(&err->first_help); |
---|
1951 | 2268 | } |
---|
1952 | 2269 | } |
---|
1953 | 2270 | |
---|
.. | .. |
---|
1956 | 2273 | int parse_events_option(const struct option *opt, const char *str, |
---|
1957 | 2274 | int unset __maybe_unused) |
---|
1958 | 2275 | { |
---|
1959 | | - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
---|
1960 | | - struct parse_events_error err = { .idx = 0, }; |
---|
1961 | | - int ret = parse_events(evlist, str, &err); |
---|
| 2276 | + struct evlist *evlist = *(struct evlist **)opt->value; |
---|
| 2277 | + struct parse_events_error err; |
---|
| 2278 | + int ret; |
---|
| 2279 | + |
---|
| 2280 | + bzero(&err, sizeof(err)); |
---|
| 2281 | + ret = parse_events(evlist, str, &err); |
---|
1962 | 2282 | |
---|
1963 | 2283 | if (ret) { |
---|
1964 | 2284 | parse_events_print_error(&err, str); |
---|
.. | .. |
---|
1968 | 2288 | return ret; |
---|
1969 | 2289 | } |
---|
1970 | 2290 | |
---|
| 2291 | +int parse_events_option_new_evlist(const struct option *opt, const char *str, int unset) |
---|
| 2292 | +{ |
---|
| 2293 | + struct evlist **evlistp = opt->value; |
---|
| 2294 | + int ret; |
---|
| 2295 | + |
---|
| 2296 | + if (*evlistp == NULL) { |
---|
| 2297 | + *evlistp = evlist__new(); |
---|
| 2298 | + |
---|
| 2299 | + if (*evlistp == NULL) { |
---|
| 2300 | + fprintf(stderr, "Not enough memory to create evlist\n"); |
---|
| 2301 | + return -1; |
---|
| 2302 | + } |
---|
| 2303 | + } |
---|
| 2304 | + |
---|
| 2305 | + ret = parse_events_option(opt, str, unset); |
---|
| 2306 | + if (ret) { |
---|
| 2307 | + evlist__delete(*evlistp); |
---|
| 2308 | + *evlistp = NULL; |
---|
| 2309 | + } |
---|
| 2310 | + |
---|
| 2311 | + return ret; |
---|
| 2312 | +} |
---|
| 2313 | + |
---|
1971 | 2314 | static int |
---|
1972 | | -foreach_evsel_in_last_glob(struct perf_evlist *evlist, |
---|
1973 | | - int (*func)(struct perf_evsel *evsel, |
---|
| 2315 | +foreach_evsel_in_last_glob(struct evlist *evlist, |
---|
| 2316 | + int (*func)(struct evsel *evsel, |
---|
1974 | 2317 | const void *arg), |
---|
1975 | 2318 | const void *arg) |
---|
1976 | 2319 | { |
---|
1977 | | - struct perf_evsel *last = NULL; |
---|
| 2320 | + struct evsel *last = NULL; |
---|
1978 | 2321 | int err; |
---|
1979 | 2322 | |
---|
1980 | 2323 | /* |
---|
.. | .. |
---|
1983 | 2326 | * |
---|
1984 | 2327 | * So no need to WARN here, let *func do this. |
---|
1985 | 2328 | */ |
---|
1986 | | - if (evlist->nr_entries > 0) |
---|
1987 | | - last = perf_evlist__last(evlist); |
---|
| 2329 | + if (evlist->core.nr_entries > 0) |
---|
| 2330 | + last = evlist__last(evlist); |
---|
1988 | 2331 | |
---|
1989 | 2332 | do { |
---|
1990 | 2333 | err = (*func)(last, arg); |
---|
.. | .. |
---|
1993 | 2336 | if (!last) |
---|
1994 | 2337 | return 0; |
---|
1995 | 2338 | |
---|
1996 | | - if (last->node.prev == &evlist->entries) |
---|
| 2339 | + if (last->core.node.prev == &evlist->core.entries) |
---|
1997 | 2340 | return 0; |
---|
1998 | | - last = list_entry(last->node.prev, struct perf_evsel, node); |
---|
| 2341 | + last = list_entry(last->core.node.prev, struct evsel, core.node); |
---|
1999 | 2342 | } while (!last->cmdline_group_boundary); |
---|
2000 | 2343 | |
---|
2001 | 2344 | return 0; |
---|
2002 | 2345 | } |
---|
2003 | 2346 | |
---|
2004 | | -static int set_filter(struct perf_evsel *evsel, const void *arg) |
---|
| 2347 | +static int set_filter(struct evsel *evsel, const void *arg) |
---|
2005 | 2348 | { |
---|
2006 | 2349 | const char *str = arg; |
---|
2007 | 2350 | bool found = false; |
---|
.. | .. |
---|
2014 | 2357 | return -1; |
---|
2015 | 2358 | } |
---|
2016 | 2359 | |
---|
2017 | | - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { |
---|
2018 | | - if (perf_evsel__append_tp_filter(evsel, str) < 0) { |
---|
| 2360 | + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { |
---|
| 2361 | + if (evsel__append_tp_filter(evsel, str) < 0) { |
---|
2019 | 2362 | fprintf(stderr, |
---|
2020 | 2363 | "not enough memory to hold filter string\n"); |
---|
2021 | 2364 | return -1; |
---|
.. | .. |
---|
2025 | 2368 | } |
---|
2026 | 2369 | |
---|
2027 | 2370 | while ((pmu = perf_pmu__scan(pmu)) != NULL) |
---|
2028 | | - if (pmu->type == evsel->attr.type) { |
---|
| 2371 | + if (pmu->type == evsel->core.attr.type) { |
---|
2029 | 2372 | found = true; |
---|
2030 | 2373 | break; |
---|
2031 | 2374 | } |
---|
.. | .. |
---|
2040 | 2383 | return -1; |
---|
2041 | 2384 | } |
---|
2042 | 2385 | |
---|
2043 | | - if (perf_evsel__append_addr_filter(evsel, str) < 0) { |
---|
| 2386 | + if (evsel__append_addr_filter(evsel, str) < 0) { |
---|
2044 | 2387 | fprintf(stderr, |
---|
2045 | 2388 | "not enough memory to hold filter string\n"); |
---|
2046 | 2389 | return -1; |
---|
.. | .. |
---|
2052 | 2395 | int parse_filter(const struct option *opt, const char *str, |
---|
2053 | 2396 | int unset __maybe_unused) |
---|
2054 | 2397 | { |
---|
2055 | | - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
---|
| 2398 | + struct evlist *evlist = *(struct evlist **)opt->value; |
---|
2056 | 2399 | |
---|
2057 | 2400 | return foreach_evsel_in_last_glob(evlist, set_filter, |
---|
2058 | 2401 | (const void *)str); |
---|
2059 | 2402 | } |
---|
2060 | 2403 | |
---|
2061 | | -static int add_exclude_perf_filter(struct perf_evsel *evsel, |
---|
| 2404 | +static int add_exclude_perf_filter(struct evsel *evsel, |
---|
2062 | 2405 | const void *arg __maybe_unused) |
---|
2063 | 2406 | { |
---|
2064 | 2407 | char new_filter[64]; |
---|
2065 | 2408 | |
---|
2066 | | - if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) { |
---|
| 2409 | + if (evsel == NULL || evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { |
---|
2067 | 2410 | fprintf(stderr, |
---|
2068 | 2411 | "--exclude-perf option should follow a -e tracepoint option\n"); |
---|
2069 | 2412 | return -1; |
---|
.. | .. |
---|
2071 | 2414 | |
---|
2072 | 2415 | snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid()); |
---|
2073 | 2416 | |
---|
2074 | | - if (perf_evsel__append_tp_filter(evsel, new_filter) < 0) { |
---|
| 2417 | + if (evsel__append_tp_filter(evsel, new_filter) < 0) { |
---|
2075 | 2418 | fprintf(stderr, |
---|
2076 | 2419 | "not enough memory to hold filter string\n"); |
---|
2077 | 2420 | return -1; |
---|
.. | .. |
---|
2084 | 2427 | const char *arg __maybe_unused, |
---|
2085 | 2428 | int unset __maybe_unused) |
---|
2086 | 2429 | { |
---|
2087 | | - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
---|
| 2430 | + struct evlist *evlist = *(struct evlist **)opt->value; |
---|
2088 | 2431 | |
---|
2089 | 2432 | return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, |
---|
2090 | 2433 | NULL); |
---|
.. | .. |
---|
2250 | 2593 | { |
---|
2251 | 2594 | bool ret = true; |
---|
2252 | 2595 | int open_return; |
---|
2253 | | - struct perf_evsel *evsel; |
---|
| 2596 | + struct evsel *evsel; |
---|
2254 | 2597 | struct perf_event_attr attr = { |
---|
2255 | 2598 | .type = type, |
---|
2256 | 2599 | .config = config, |
---|
2257 | 2600 | .disabled = 1, |
---|
2258 | 2601 | }; |
---|
2259 | | - struct thread_map *tmap = thread_map__new_by_tid(0); |
---|
| 2602 | + struct perf_thread_map *tmap = thread_map__new_by_tid(0); |
---|
2260 | 2603 | |
---|
2261 | 2604 | if (tmap == NULL) |
---|
2262 | 2605 | return false; |
---|
2263 | 2606 | |
---|
2264 | | - evsel = perf_evsel__new(&attr); |
---|
| 2607 | + evsel = evsel__new(&attr); |
---|
2265 | 2608 | if (evsel) { |
---|
2266 | | - open_return = perf_evsel__open(evsel, NULL, tmap); |
---|
| 2609 | + open_return = evsel__open(evsel, NULL, tmap); |
---|
2267 | 2610 | ret = open_return >= 0; |
---|
2268 | 2611 | |
---|
2269 | 2612 | if (open_return == -EACCES) { |
---|
.. | .. |
---|
2274 | 2617 | * by default as some ARM machines do not support it. |
---|
2275 | 2618 | * |
---|
2276 | 2619 | */ |
---|
2277 | | - evsel->attr.exclude_kernel = 1; |
---|
2278 | | - ret = perf_evsel__open(evsel, NULL, tmap) >= 0; |
---|
| 2620 | + evsel->core.attr.exclude_kernel = 1; |
---|
| 2621 | + ret = evsel__open(evsel, NULL, tmap) >= 0; |
---|
2279 | 2622 | } |
---|
2280 | | - perf_evsel__delete(evsel); |
---|
| 2623 | + evsel__delete(evsel); |
---|
2281 | 2624 | } |
---|
2282 | 2625 | |
---|
2283 | | - thread_map__put(tmap); |
---|
| 2626 | + perf_thread_map__put(tmap); |
---|
2284 | 2627 | return ret; |
---|
2285 | 2628 | } |
---|
2286 | 2629 | |
---|
.. | .. |
---|
2381 | 2724 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { |
---|
2382 | 2725 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { |
---|
2383 | 2726 | /* skip invalid cache type */ |
---|
2384 | | - if (!perf_evsel__is_cache_op_valid(type, op)) |
---|
| 2727 | + if (!evsel__is_cache_op_valid(type, op)) |
---|
2385 | 2728 | continue; |
---|
2386 | 2729 | |
---|
2387 | 2730 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
---|
2388 | | - __perf_evsel__hw_cache_type_op_res_name(type, op, i, |
---|
2389 | | - name, sizeof(name)); |
---|
| 2731 | + __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); |
---|
2390 | 2732 | if (event_glob != NULL && !strglobmatch(name, event_glob)) |
---|
2391 | 2733 | continue; |
---|
2392 | 2734 | |
---|
.. | .. |
---|
2436 | 2778 | if (evt_list) |
---|
2437 | 2779 | goto out_free; |
---|
2438 | 2780 | return evt_num; |
---|
| 2781 | +} |
---|
| 2782 | + |
---|
| 2783 | +static void print_tool_event(const char *name, const char *event_glob, |
---|
| 2784 | + bool name_only) |
---|
| 2785 | +{ |
---|
| 2786 | + if (event_glob && !strglobmatch(name, event_glob)) |
---|
| 2787 | + return; |
---|
| 2788 | + if (name_only) |
---|
| 2789 | + printf("%s ", name); |
---|
| 2790 | + else |
---|
| 2791 | + printf(" %-50s [%s]\n", name, "Tool event"); |
---|
| 2792 | + |
---|
| 2793 | +} |
---|
| 2794 | + |
---|
| 2795 | +void print_tool_events(const char *event_glob, bool name_only) |
---|
| 2796 | +{ |
---|
| 2797 | + print_tool_event("duration_time", event_glob, name_only); |
---|
| 2798 | + if (pager_in_use()) |
---|
| 2799 | + printf("\n"); |
---|
2439 | 2800 | } |
---|
2440 | 2801 | |
---|
2441 | 2802 | void print_symbol_events(const char *event_glob, unsigned type, |
---|
.. | .. |
---|
2514 | 2875 | * Print the help text for the event symbols: |
---|
2515 | 2876 | */ |
---|
2516 | 2877 | void print_events(const char *event_glob, bool name_only, bool quiet_flag, |
---|
2517 | | - bool long_desc, bool details_flag) |
---|
| 2878 | + bool long_desc, bool details_flag, bool deprecated) |
---|
2518 | 2879 | { |
---|
2519 | 2880 | print_symbol_events(event_glob, PERF_TYPE_HARDWARE, |
---|
2520 | 2881 | event_symbols_hw, PERF_COUNT_HW_MAX, name_only); |
---|
2521 | 2882 | |
---|
2522 | 2883 | print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, |
---|
2523 | 2884 | event_symbols_sw, PERF_COUNT_SW_MAX, name_only); |
---|
| 2885 | + print_tool_events(event_glob, name_only); |
---|
2524 | 2886 | |
---|
2525 | 2887 | print_hwcache_events(event_glob, name_only); |
---|
2526 | 2888 | |
---|
2527 | 2889 | print_pmu_events(event_glob, name_only, quiet_flag, long_desc, |
---|
2528 | | - details_flag); |
---|
| 2890 | + details_flag, deprecated); |
---|
2529 | 2891 | |
---|
2530 | 2892 | if (event_glob != NULL) |
---|
2531 | 2893 | return; |
---|
.. | .. |
---|
2551 | 2913 | |
---|
2552 | 2914 | print_sdt_events(NULL, NULL, name_only); |
---|
2553 | 2915 | |
---|
2554 | | - metricgroup__print(true, true, NULL, name_only); |
---|
| 2916 | + metricgroup__print(true, true, NULL, name_only, details_flag); |
---|
| 2917 | + |
---|
| 2918 | + print_libpfm_events(name_only, long_desc); |
---|
2555 | 2919 | } |
---|
2556 | 2920 | |
---|
2557 | 2921 | int parse_events__is_hardcoded_term(struct parse_events_term *term) |
---|
.. | .. |
---|
2678 | 3042 | return new_term(new, &temp, str, 0); |
---|
2679 | 3043 | } |
---|
2680 | 3044 | |
---|
| 3045 | +void parse_events_term__delete(struct parse_events_term *term) |
---|
| 3046 | +{ |
---|
| 3047 | + if (term->array.nr_ranges) |
---|
| 3048 | + zfree(&term->array.ranges); |
---|
| 3049 | + |
---|
| 3050 | + if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) |
---|
| 3051 | + zfree(&term->val.str); |
---|
| 3052 | + |
---|
| 3053 | + zfree(&term->config); |
---|
| 3054 | + free(term); |
---|
| 3055 | +} |
---|
| 3056 | + |
---|
2681 | 3057 | int parse_events_copy_term_list(struct list_head *old, |
---|
2682 | 3058 | struct list_head **new) |
---|
2683 | 3059 | { |
---|
.. | .. |
---|
2708 | 3084 | struct parse_events_term *term, *h; |
---|
2709 | 3085 | |
---|
2710 | 3086 | list_for_each_entry_safe(term, h, terms, list) { |
---|
2711 | | - if (term->array.nr_ranges) |
---|
2712 | | - zfree(&term->array.ranges); |
---|
2713 | 3087 | list_del_init(&term->list); |
---|
2714 | | - free(term); |
---|
| 3088 | + parse_events_term__delete(term); |
---|
2715 | 3089 | } |
---|
2716 | 3090 | } |
---|
2717 | 3091 | |
---|
.. | .. |
---|
2731 | 3105 | void parse_events_evlist_error(struct parse_events_state *parse_state, |
---|
2732 | 3106 | int idx, const char *str) |
---|
2733 | 3107 | { |
---|
2734 | | - struct parse_events_error *err = parse_state->error; |
---|
2735 | | - |
---|
2736 | | - if (!err) |
---|
| 3108 | + if (!parse_state->error) |
---|
2737 | 3109 | return; |
---|
2738 | | - err->idx = idx; |
---|
2739 | | - err->str = strdup(str); |
---|
2740 | | - WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); |
---|
| 3110 | + |
---|
| 3111 | + parse_events__handle_error(parse_state->error, idx, strdup(str), NULL); |
---|
2741 | 3112 | } |
---|
2742 | 3113 | |
---|
2743 | 3114 | static void config_terms_list(char *buf, size_t buf_sz) |
---|