| .. | .. |
|---|
| 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) |
|---|