.. | .. |
---|
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 | { |
---|
.. | .. |
---|
223 | 260 | path = zalloc(sizeof(*path)); |
---|
224 | 261 | if (!path) |
---|
225 | 262 | return NULL; |
---|
226 | | - path->system = malloc(MAX_EVENT_LENGTH); |
---|
227 | | - if (!path->system) { |
---|
| 263 | + if (asprintf(&path->system, "%.*s", MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) { |
---|
228 | 264 | free(path); |
---|
229 | 265 | return NULL; |
---|
230 | 266 | } |
---|
231 | | - path->name = malloc(MAX_EVENT_LENGTH); |
---|
232 | | - if (!path->name) { |
---|
| 267 | + if (asprintf(&path->name, "%.*s", MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) { |
---|
233 | 268 | zfree(&path->system); |
---|
234 | 269 | free(path); |
---|
235 | 270 | return NULL; |
---|
236 | 271 | } |
---|
237 | | - strncpy(path->system, sys_dirent->d_name, |
---|
238 | | - MAX_EVENT_LENGTH); |
---|
239 | | - strncpy(path->name, evt_dirent->d_name, |
---|
240 | | - MAX_EVENT_LENGTH); |
---|
241 | 272 | return path; |
---|
242 | 273 | } |
---|
243 | 274 | } |
---|
.. | .. |
---|
313 | 344 | return NULL; |
---|
314 | 345 | } |
---|
315 | 346 | |
---|
316 | | -static struct perf_evsel * |
---|
| 347 | +static struct evsel * |
---|
317 | 348 | __add_event(struct list_head *list, int *idx, |
---|
318 | 349 | struct perf_event_attr *attr, |
---|
| 350 | + bool init_attr, |
---|
319 | 351 | char *name, struct perf_pmu *pmu, |
---|
320 | | - struct list_head *config_terms, bool auto_merge_stats) |
---|
| 352 | + struct list_head *config_terms, bool auto_merge_stats, |
---|
| 353 | + const char *cpu_list) |
---|
321 | 354 | { |
---|
322 | | - struct perf_evsel *evsel; |
---|
323 | | - 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; |
---|
324 | 358 | |
---|
325 | | - event_attr_init(attr); |
---|
| 359 | + if (pmu) |
---|
| 360 | + perf_pmu__warn_invalid_formats(pmu); |
---|
326 | 361 | |
---|
327 | | - evsel = perf_evsel__new_idx(attr, *idx); |
---|
328 | | - 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); |
---|
329 | 371 | return NULL; |
---|
| 372 | + } |
---|
330 | 373 | |
---|
331 | 374 | (*idx)++; |
---|
332 | | - evsel->cpus = cpu_map__get(cpus); |
---|
333 | | - evsel->own_cpus = cpu_map__get(cpus); |
---|
334 | | - 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; |
---|
335 | 378 | evsel->auto_merge_stats = auto_merge_stats; |
---|
336 | 379 | |
---|
337 | 380 | if (name) |
---|
.. | .. |
---|
340 | 383 | if (config_terms) |
---|
341 | 384 | list_splice(config_terms, &evsel->config_terms); |
---|
342 | 385 | |
---|
343 | | - list_add_tail(&evsel->node, list); |
---|
| 386 | + if (list) |
---|
| 387 | + list_add_tail(&evsel->core.node, list); |
---|
| 388 | + |
---|
344 | 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); |
---|
345 | 397 | } |
---|
346 | 398 | |
---|
347 | 399 | static int add_event(struct list_head *list, int *idx, |
---|
348 | 400 | struct perf_event_attr *attr, char *name, |
---|
349 | 401 | struct list_head *config_terms) |
---|
350 | 402 | { |
---|
351 | | - 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; |
---|
352 | 405 | } |
---|
353 | 406 | |
---|
354 | | -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) |
---|
355 | 427 | { |
---|
356 | 428 | int i, j; |
---|
357 | 429 | int n, longest = -1; |
---|
358 | 430 | |
---|
359 | 431 | for (i = 0; i < size; i++) { |
---|
360 | | - for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) { |
---|
| 432 | + for (j = 0; j < EVSEL__MAX_ALIASES && names[i][j]; j++) { |
---|
361 | 433 | n = strlen(names[i][j]); |
---|
362 | 434 | if (n > longest && !strncasecmp(str, names[i][j], n)) |
---|
363 | 435 | longest = n; |
---|
.. | .. |
---|
396 | 468 | * No fallback - if we cannot get a clear cache type |
---|
397 | 469 | * then bail out: |
---|
398 | 470 | */ |
---|
399 | | - cache_type = parse_aliases(type, perf_evsel__hw_cache, |
---|
400 | | - PERF_COUNT_HW_CACHE_MAX); |
---|
| 471 | + cache_type = parse_aliases(type, evsel__hw_cache, PERF_COUNT_HW_CACHE_MAX); |
---|
401 | 472 | if (cache_type == -1) |
---|
402 | 473 | return -EINVAL; |
---|
403 | 474 | |
---|
.. | .. |
---|
410 | 481 | n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str); |
---|
411 | 482 | |
---|
412 | 483 | if (cache_op == -1) { |
---|
413 | | - cache_op = parse_aliases(str, perf_evsel__hw_cache_op, |
---|
| 484 | + cache_op = parse_aliases(str, evsel__hw_cache_op, |
---|
414 | 485 | PERF_COUNT_HW_CACHE_OP_MAX); |
---|
415 | 486 | if (cache_op >= 0) { |
---|
416 | | - if (!perf_evsel__is_cache_op_valid(cache_type, cache_op)) |
---|
| 487 | + if (!evsel__is_cache_op_valid(cache_type, cache_op)) |
---|
417 | 488 | return -EINVAL; |
---|
418 | 489 | continue; |
---|
419 | 490 | } |
---|
420 | 491 | } |
---|
421 | 492 | |
---|
422 | 493 | if (cache_result == -1) { |
---|
423 | | - cache_result = parse_aliases(str, perf_evsel__hw_cache_result, |
---|
| 494 | + cache_result = parse_aliases(str, evsel__hw_cache_result, |
---|
424 | 495 | PERF_COUNT_HW_CACHE_RESULT_MAX); |
---|
425 | 496 | if (cache_result >= 0) |
---|
426 | 497 | continue; |
---|
.. | .. |
---|
457 | 528 | static void tracepoint_error(struct parse_events_error *e, int err, |
---|
458 | 529 | const char *sys, const char *name) |
---|
459 | 530 | { |
---|
| 531 | + const char *str; |
---|
460 | 532 | char help[BUFSIZ]; |
---|
461 | 533 | |
---|
462 | 534 | if (!e) |
---|
.. | .. |
---|
470 | 542 | |
---|
471 | 543 | switch (err) { |
---|
472 | 544 | case EACCES: |
---|
473 | | - e->str = strdup("can't access trace events"); |
---|
| 545 | + str = "can't access trace events"; |
---|
474 | 546 | break; |
---|
475 | 547 | case ENOENT: |
---|
476 | | - e->str = strdup("unknown tracepoint"); |
---|
| 548 | + str = "unknown tracepoint"; |
---|
477 | 549 | break; |
---|
478 | 550 | default: |
---|
479 | | - e->str = strdup("failed to add tracepoint"); |
---|
| 551 | + str = "failed to add tracepoint"; |
---|
480 | 552 | break; |
---|
481 | 553 | } |
---|
482 | 554 | |
---|
483 | 555 | tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); |
---|
484 | | - e->help = strdup(help); |
---|
| 556 | + parse_events__handle_error(e, 0, strdup(str), strdup(help)); |
---|
485 | 557 | } |
---|
486 | 558 | |
---|
487 | 559 | static int add_tracepoint(struct list_head *list, int *idx, |
---|
.. | .. |
---|
489 | 561 | struct parse_events_error *err, |
---|
490 | 562 | struct list_head *head_config) |
---|
491 | 563 | { |
---|
492 | | - struct perf_evsel *evsel; |
---|
| 564 | + struct evsel *evsel = evsel__newtp_idx(sys_name, evt_name, (*idx)++); |
---|
493 | 565 | |
---|
494 | | - evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); |
---|
495 | 566 | if (IS_ERR(evsel)) { |
---|
496 | 567 | tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name); |
---|
497 | 568 | return PTR_ERR(evsel); |
---|
.. | .. |
---|
505 | 576 | list_splice(&config_terms, &evsel->config_terms); |
---|
506 | 577 | } |
---|
507 | 578 | |
---|
508 | | - list_add_tail(&evsel->node, list); |
---|
| 579 | + list_add_tail(&evsel->core.node, list); |
---|
509 | 580 | return 0; |
---|
510 | 581 | } |
---|
511 | 582 | |
---|
.. | .. |
---|
609 | 680 | struct list_head *head_config; |
---|
610 | 681 | }; |
---|
611 | 682 | |
---|
612 | | -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, |
---|
613 | 684 | void *_param) |
---|
614 | 685 | { |
---|
615 | 686 | LIST_HEAD(new_evsels); |
---|
616 | 687 | struct __add_bpf_event_param *param = _param; |
---|
617 | 688 | struct parse_events_state *parse_state = param->parse_state; |
---|
618 | 689 | struct list_head *list = param->list; |
---|
619 | | - struct perf_evsel *pos; |
---|
| 690 | + struct evsel *pos; |
---|
620 | 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; |
---|
621 | 701 | |
---|
622 | 702 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", |
---|
623 | 703 | group, event, fd); |
---|
.. | .. |
---|
626 | 706 | event, parse_state->error, |
---|
627 | 707 | param->head_config); |
---|
628 | 708 | if (err) { |
---|
629 | | - struct perf_evsel *evsel, *tmp; |
---|
| 709 | + struct evsel *evsel, *tmp; |
---|
630 | 710 | |
---|
631 | 711 | pr_debug("Failed to add BPF event %s:%s\n", |
---|
632 | 712 | group, event); |
---|
633 | | - list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { |
---|
634 | | - list_del(&evsel->node); |
---|
635 | | - 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); |
---|
636 | 716 | } |
---|
637 | 717 | return err; |
---|
638 | 718 | } |
---|
639 | 719 | pr_debug("adding %s:%s\n", group, event); |
---|
640 | 720 | |
---|
641 | | - list_for_each_entry(pos, &new_evsels, node) { |
---|
| 721 | + list_for_each_entry(pos, &new_evsels, core.node) { |
---|
642 | 722 | pr_debug("adding %s:%s to %p\n", |
---|
643 | 723 | group, event, pos); |
---|
644 | 724 | pos->bpf_fd = fd; |
---|
| 725 | + pos->bpf_obj = obj; |
---|
645 | 726 | } |
---|
646 | 727 | list_splice(&new_evsels, list); |
---|
647 | 728 | return 0; |
---|
.. | .. |
---|
695 | 776 | |
---|
696 | 777 | return 0; |
---|
697 | 778 | errout: |
---|
698 | | - parse_state->error->help = strdup("(add -v to see detail)"); |
---|
699 | | - parse_state->error->str = strdup(errbuf); |
---|
| 779 | + parse_events__handle_error(parse_state->error, 0, |
---|
| 780 | + strdup(errbuf), strdup("(add -v to see detail)")); |
---|
700 | 781 | return err; |
---|
701 | 782 | } |
---|
702 | 783 | |
---|
.. | .. |
---|
712 | 793 | return 0; |
---|
713 | 794 | |
---|
714 | 795 | list_for_each_entry(term, head_config, list) { |
---|
715 | | - char errbuf[BUFSIZ]; |
---|
716 | 796 | int err; |
---|
717 | 797 | |
---|
718 | 798 | if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) { |
---|
719 | | - snprintf(errbuf, sizeof(errbuf), |
---|
720 | | - "Invalid config term for BPF object"); |
---|
721 | | - errbuf[BUFSIZ - 1] = '\0'; |
---|
722 | | - |
---|
723 | | - parse_state->error->idx = term->err_term; |
---|
724 | | - 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); |
---|
725 | 802 | return -EINVAL; |
---|
726 | 803 | } |
---|
727 | 804 | |
---|
728 | 805 | err = bpf__config_obj(obj, term, parse_state->evlist, &error_pos); |
---|
729 | 806 | if (err) { |
---|
| 807 | + char errbuf[BUFSIZ]; |
---|
| 808 | + int idx; |
---|
| 809 | + |
---|
730 | 810 | bpf__strerror_config_obj(obj, term, parse_state->evlist, |
---|
731 | 811 | &error_pos, err, errbuf, |
---|
732 | 812 | sizeof(errbuf)); |
---|
733 | | - 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( |
---|
734 | 822 | "Hint:\tValid config terms:\n" |
---|
735 | 823 | " \tmap:[<arraymap>].value<indices>=[value]\n" |
---|
736 | 824 | " \tmap:[<eventmap>].event<indices>=[event]\n" |
---|
737 | 825 | "\n" |
---|
738 | 826 | " \twhere <indices> is something like [0,3...5] or [all]\n" |
---|
739 | | -" \t(add -v to see detail)"); |
---|
740 | | - parse_state->error->str = strdup(errbuf); |
---|
741 | | - if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE) |
---|
742 | | - parse_state->error->idx = term->err_val; |
---|
743 | | - else |
---|
744 | | - parse_state->error->idx = term->err_term + error_pos; |
---|
| 827 | +" \t(add -v to see detail)")); |
---|
745 | 828 | return err; |
---|
746 | 829 | } |
---|
747 | 830 | } |
---|
.. | .. |
---|
805 | 888 | -err, errbuf, |
---|
806 | 889 | sizeof(errbuf)); |
---|
807 | 890 | |
---|
808 | | - parse_state->error->help = strdup("(add -v to see detail)"); |
---|
809 | | - parse_state->error->str = strdup(errbuf); |
---|
| 891 | + parse_events__handle_error(parse_state->error, 0, |
---|
| 892 | + strdup(errbuf), strdup("(add -v to see detail)")); |
---|
810 | 893 | return err; |
---|
811 | 894 | } |
---|
812 | 895 | |
---|
.. | .. |
---|
865 | 948 | } |
---|
866 | 949 | |
---|
867 | 950 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
---|
868 | | - void *ptr, char *type, u64 len) |
---|
| 951 | + u64 addr, char *type, u64 len) |
---|
869 | 952 | { |
---|
870 | 953 | struct perf_event_attr attr; |
---|
871 | 954 | |
---|
872 | 955 | memset(&attr, 0, sizeof(attr)); |
---|
873 | | - attr.bp_addr = (unsigned long) ptr; |
---|
| 956 | + attr.bp_addr = addr; |
---|
874 | 957 | |
---|
875 | 958 | if (parse_breakpoint_type(type, &attr)) |
---|
876 | 959 | return -EINVAL; |
---|
.. | .. |
---|
899 | 982 | return 0; |
---|
900 | 983 | |
---|
901 | 984 | if (err) { |
---|
902 | | - err->idx = term->err_val; |
---|
903 | | - if (type == PARSE_EVENTS__TERM_TYPE_NUM) |
---|
904 | | - err->str = strdup("expected numeric value"); |
---|
905 | | - else |
---|
906 | | - 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); |
---|
907 | 990 | } |
---|
908 | 991 | return -EINVAL; |
---|
909 | 992 | } |
---|
.. | .. |
---|
926 | 1009 | [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit", |
---|
927 | 1010 | [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit", |
---|
928 | 1011 | [PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack", |
---|
| 1012 | + [PARSE_EVENTS__TERM_TYPE_MAX_EVENTS] = "nr", |
---|
929 | 1013 | [PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite", |
---|
930 | 1014 | [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", |
---|
931 | 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", |
---|
932 | 1019 | }; |
---|
933 | 1020 | |
---|
934 | 1021 | static bool config_term_shrinked; |
---|
.. | .. |
---|
936 | 1023 | static bool |
---|
937 | 1024 | config_term_avail(int term_type, struct parse_events_error *err) |
---|
938 | 1025 | { |
---|
| 1026 | + char *err_str; |
---|
| 1027 | + |
---|
939 | 1028 | if (term_type < 0 || term_type >= __PARSE_EVENTS__TERM_TYPE_NR) { |
---|
940 | | - err->str = strdup("Invalid term_type"); |
---|
| 1029 | + parse_events__handle_error(err, -1, |
---|
| 1030 | + strdup("Invalid term_type"), NULL); |
---|
941 | 1031 | return false; |
---|
942 | 1032 | } |
---|
943 | 1033 | if (!config_term_shrinked) |
---|
.. | .. |
---|
949 | 1039 | case PARSE_EVENTS__TERM_TYPE_CONFIG2: |
---|
950 | 1040 | case PARSE_EVENTS__TERM_TYPE_NAME: |
---|
951 | 1041 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
---|
| 1042 | + case PARSE_EVENTS__TERM_TYPE_PERCORE: |
---|
952 | 1043 | return true; |
---|
953 | 1044 | default: |
---|
954 | 1045 | if (!err) |
---|
955 | 1046 | return false; |
---|
956 | 1047 | |
---|
957 | 1048 | /* term_type is validated so indexing is safe */ |
---|
958 | | - if (asprintf(&err->str, "'%s' is not usable in 'perf stat'", |
---|
959 | | - config_term_names[term_type]) < 0) |
---|
960 | | - 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); |
---|
961 | 1052 | return false; |
---|
962 | 1053 | } |
---|
963 | 1054 | } |
---|
.. | .. |
---|
999 | 1090 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: |
---|
1000 | 1091 | CHECK_TYPE_VAL(STR); |
---|
1001 | 1092 | if (strcmp(term->val.str, "no") && |
---|
1002 | | - parse_branch_str(term->val.str, &attr->branch_sample_type)) { |
---|
1003 | | - err->str = strdup("invalid branch sample type"); |
---|
1004 | | - 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); |
---|
1005 | 1098 | return -EINVAL; |
---|
1006 | 1099 | } |
---|
1007 | 1100 | break; |
---|
1008 | 1101 | case PARSE_EVENTS__TERM_TYPE_TIME: |
---|
1009 | 1102 | CHECK_TYPE_VAL(NUM); |
---|
1010 | 1103 | if (term->val.num > 1) { |
---|
1011 | | - err->str = strdup("expected 0 or 1"); |
---|
1012 | | - err->idx = term->err_val; |
---|
| 1104 | + parse_events__handle_error(err, term->err_val, |
---|
| 1105 | + strdup("expected 0 or 1"), |
---|
| 1106 | + NULL); |
---|
1013 | 1107 | return -EINVAL; |
---|
1014 | 1108 | } |
---|
1015 | 1109 | break; |
---|
.. | .. |
---|
1037 | 1131 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
---|
1038 | 1132 | CHECK_TYPE_VAL(NUM); |
---|
1039 | 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; |
---|
1040 | 1158 | default: |
---|
1041 | | - err->str = strdup("unknown term"); |
---|
1042 | | - err->idx = term->err_term; |
---|
1043 | | - 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)); |
---|
1044 | 1162 | return -EINVAL; |
---|
1045 | 1163 | } |
---|
1046 | 1164 | |
---|
.. | .. |
---|
1084 | 1202 | case PARSE_EVENTS__TERM_TYPE_INHERIT: |
---|
1085 | 1203 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
---|
1086 | 1204 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
---|
| 1205 | + case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: |
---|
1087 | 1206 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: |
---|
1088 | 1207 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: |
---|
| 1208 | + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: |
---|
| 1209 | + case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE: |
---|
1089 | 1210 | return config_term_common(attr, term, err); |
---|
1090 | 1211 | default: |
---|
1091 | 1212 | if (err) { |
---|
1092 | | - err->idx = term->err_term; |
---|
1093 | | - err->str = strdup("unknown term"); |
---|
1094 | | - 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")); |
---|
1095 | 1216 | } |
---|
1096 | 1217 | return -EINVAL; |
---|
1097 | 1218 | } |
---|
.. | .. |
---|
1116 | 1237 | static int get_config_terms(struct list_head *head_config, |
---|
1117 | 1238 | struct list_head *head_terms __maybe_unused) |
---|
1118 | 1239 | { |
---|
1119 | | -#define ADD_CONFIG_TERM(__type, __name, __val) \ |
---|
1120 | | -do { \ |
---|
1121 | | - struct perf_evsel_config_term *__t; \ |
---|
| 1240 | +#define ADD_CONFIG_TERM(__type, __weak) \ |
---|
| 1241 | + struct evsel_config_term *__t; \ |
---|
1122 | 1242 | \ |
---|
1123 | 1243 | __t = zalloc(sizeof(*__t)); \ |
---|
1124 | 1244 | if (!__t) \ |
---|
1125 | 1245 | return -ENOMEM; \ |
---|
1126 | 1246 | \ |
---|
1127 | 1247 | INIT_LIST_HEAD(&__t->list); \ |
---|
1128 | | - __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); \ |
---|
1129 | 1255 | __t->val.__name = __val; \ |
---|
1130 | | - __t->weak = term->weak; \ |
---|
1131 | | - 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; \ |
---|
1132 | 1267 | } while (0) |
---|
1133 | 1268 | |
---|
1134 | 1269 | struct parse_events_term *term; |
---|
.. | .. |
---|
1136 | 1271 | list_for_each_entry(term, head_config, list) { |
---|
1137 | 1272 | switch (term->type_term) { |
---|
1138 | 1273 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: |
---|
1139 | | - ADD_CONFIG_TERM(PERIOD, period, term->val.num); |
---|
| 1274 | + ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak); |
---|
1140 | 1275 | break; |
---|
1141 | 1276 | case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ: |
---|
1142 | | - ADD_CONFIG_TERM(FREQ, freq, term->val.num); |
---|
| 1277 | + ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak); |
---|
1143 | 1278 | break; |
---|
1144 | 1279 | case PARSE_EVENTS__TERM_TYPE_TIME: |
---|
1145 | | - ADD_CONFIG_TERM(TIME, time, term->val.num); |
---|
| 1280 | + ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak); |
---|
1146 | 1281 | break; |
---|
1147 | 1282 | case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: |
---|
1148 | | - ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str); |
---|
| 1283 | + ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak); |
---|
1149 | 1284 | break; |
---|
1150 | 1285 | case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: |
---|
1151 | | - ADD_CONFIG_TERM(BRANCH, branch, term->val.str); |
---|
| 1286 | + ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak); |
---|
1152 | 1287 | break; |
---|
1153 | 1288 | case PARSE_EVENTS__TERM_TYPE_STACKSIZE: |
---|
1154 | | - 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); |
---|
1155 | 1291 | break; |
---|
1156 | 1292 | case PARSE_EVENTS__TERM_TYPE_INHERIT: |
---|
1157 | | - 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); |
---|
1158 | 1295 | break; |
---|
1159 | 1296 | case PARSE_EVENTS__TERM_TYPE_NOINHERIT: |
---|
1160 | | - 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); |
---|
1161 | 1299 | break; |
---|
1162 | 1300 | case PARSE_EVENTS__TERM_TYPE_MAX_STACK: |
---|
1163 | | - 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); |
---|
1164 | 1307 | break; |
---|
1165 | 1308 | case PARSE_EVENTS__TERM_TYPE_OVERWRITE: |
---|
1166 | | - 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); |
---|
1167 | 1311 | break; |
---|
1168 | 1312 | case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: |
---|
1169 | | - 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); |
---|
1170 | 1315 | break; |
---|
1171 | 1316 | case PARSE_EVENTS__TERM_TYPE_DRV_CFG: |
---|
1172 | | - 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); |
---|
1173 | 1330 | break; |
---|
1174 | 1331 | default: |
---|
1175 | 1332 | break; |
---|
1176 | 1333 | } |
---|
1177 | 1334 | } |
---|
1178 | | -#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 |
---|
1179 | 1369 | return 0; |
---|
1180 | 1370 | } |
---|
1181 | 1371 | |
---|
.. | .. |
---|
1225 | 1415 | get_config_name(head_config), &config_terms); |
---|
1226 | 1416 | } |
---|
1227 | 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 | + |
---|
1228 | 1437 | int parse_events_add_pmu(struct parse_events_state *parse_state, |
---|
1229 | 1438 | struct list_head *list, char *name, |
---|
1230 | 1439 | struct list_head *head_config, |
---|
.. | .. |
---|
1234 | 1443 | struct perf_event_attr attr; |
---|
1235 | 1444 | struct perf_pmu_info info; |
---|
1236 | 1445 | struct perf_pmu *pmu; |
---|
1237 | | - struct perf_evsel *evsel; |
---|
| 1446 | + struct evsel *evsel; |
---|
1238 | 1447 | struct parse_events_error *err = parse_state->error; |
---|
1239 | 1448 | bool use_uncore_alias; |
---|
1240 | 1449 | LIST_HEAD(config_terms); |
---|
1241 | 1450 | |
---|
1242 | | - 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 | + |
---|
1243 | 1466 | if (!pmu) { |
---|
1244 | | - if (asprintf(&err->str, |
---|
| 1467 | + char *err_str; |
---|
| 1468 | + |
---|
| 1469 | + if (asprintf(&err_str, |
---|
1245 | 1470 | "Cannot find PMU `%s'. Missing kernel support?", |
---|
1246 | | - name) < 0) |
---|
1247 | | - err->str = NULL; |
---|
| 1471 | + name) >= 0) |
---|
| 1472 | + parse_events__handle_error(err, 0, err_str, NULL); |
---|
1248 | 1473 | return -EINVAL; |
---|
1249 | 1474 | } |
---|
1250 | 1475 | |
---|
.. | .. |
---|
1259 | 1484 | |
---|
1260 | 1485 | if (!head_config) { |
---|
1261 | 1486 | attr.type = pmu->type; |
---|
1262 | | - 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); |
---|
1263 | 1489 | if (evsel) { |
---|
1264 | 1490 | evsel->pmu_name = name ? strdup(name) : NULL; |
---|
1265 | 1491 | evsel->use_uncore_alias = use_uncore_alias; |
---|
.. | .. |
---|
1269 | 1495 | } |
---|
1270 | 1496 | } |
---|
1271 | 1497 | |
---|
1272 | | - if (perf_pmu__check_alias(pmu, head_config, &info)) |
---|
| 1498 | + if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, head_config, &info)) |
---|
1273 | 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 | + } |
---|
1274 | 1513 | |
---|
1275 | 1514 | /* |
---|
1276 | 1515 | * Configure hardcoded terms first, no need to check |
---|
.. | .. |
---|
1282 | 1521 | if (get_config_terms(head_config, &config_terms)) |
---|
1283 | 1522 | return -ENOMEM; |
---|
1284 | 1523 | |
---|
1285 | | - if (perf_pmu__config(pmu, &attr, head_config, parse_state->error)) { |
---|
1286 | | - 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; |
---|
1287 | 1533 | |
---|
1288 | 1534 | list_for_each_entry_safe(pos, tmp, &config_terms, list) { |
---|
1289 | 1535 | list_del_init(&pos->list); |
---|
| 1536 | + if (pos->free_str) |
---|
| 1537 | + zfree(&pos->val.str); |
---|
1290 | 1538 | free(pos); |
---|
1291 | 1539 | } |
---|
1292 | 1540 | return -EINVAL; |
---|
1293 | 1541 | } |
---|
1294 | 1542 | |
---|
1295 | | - evsel = __add_event(list, &parse_state->idx, &attr, |
---|
| 1543 | + evsel = __add_event(list, &parse_state->idx, &attr, true, |
---|
1296 | 1544 | get_config_name(head_config), pmu, |
---|
1297 | | - &config_terms, auto_merge_stats); |
---|
1298 | | - if (evsel) { |
---|
1299 | | - evsel->unit = info.unit; |
---|
1300 | | - evsel->scale = info.scale; |
---|
1301 | | - evsel->per_pkg = info.per_pkg; |
---|
1302 | | - evsel->snapshot = info.snapshot; |
---|
1303 | | - evsel->metric_expr = info.metric_expr; |
---|
1304 | | - evsel->metric_name = info.metric_name; |
---|
1305 | | - evsel->pmu_name = name ? strdup(name) : NULL; |
---|
1306 | | - evsel->use_uncore_alias = use_uncore_alias; |
---|
1307 | | - } |
---|
| 1545 | + &config_terms, auto_merge_stats, NULL); |
---|
| 1546 | + if (!evsel) |
---|
| 1547 | + return -ENOMEM; |
---|
1308 | 1548 | |
---|
1309 | | - 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; |
---|
1310 | 1563 | } |
---|
1311 | 1564 | |
---|
1312 | 1565 | int parse_events_multi_pmu_add(struct parse_events_state *parse_state, |
---|
1313 | 1566 | char *str, struct list_head **listp) |
---|
1314 | 1567 | { |
---|
1315 | | - struct list_head *head; |
---|
1316 | 1568 | struct parse_events_term *term; |
---|
1317 | 1569 | struct list_head *list; |
---|
1318 | 1570 | struct perf_pmu *pmu = NULL; |
---|
.. | .. |
---|
1329 | 1581 | |
---|
1330 | 1582 | list_for_each_entry(alias, &pmu->aliases, list) { |
---|
1331 | 1583 | if (!strcasecmp(alias->name, str)) { |
---|
| 1584 | + struct list_head *head; |
---|
| 1585 | + char *config; |
---|
| 1586 | + |
---|
1332 | 1587 | head = malloc(sizeof(struct list_head)); |
---|
1333 | 1588 | if (!head) |
---|
1334 | 1589 | return -1; |
---|
1335 | 1590 | INIT_LIST_HEAD(head); |
---|
1336 | | - if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, |
---|
1337 | | - str, 1, false, &str, NULL) < 0) |
---|
| 1591 | + config = strdup(str); |
---|
| 1592 | + if (!config) |
---|
1338 | 1593 | return -1; |
---|
| 1594 | + if (parse_events_term__num(&term, |
---|
| 1595 | + PARSE_EVENTS__TERM_TYPE_USER, |
---|
| 1596 | + config, 1, false, &config, |
---|
| 1597 | + NULL) < 0) { |
---|
| 1598 | + free(list); |
---|
| 1599 | + free(config); |
---|
| 1600 | + return -1; |
---|
| 1601 | + } |
---|
1339 | 1602 | list_add_tail(&term->list, head); |
---|
1340 | 1603 | |
---|
1341 | 1604 | if (!parse_events_add_pmu(parse_state, list, |
---|
.. | .. |
---|
1350 | 1613 | } |
---|
1351 | 1614 | } |
---|
1352 | 1615 | } |
---|
1353 | | - if (!ok) |
---|
| 1616 | + if (!ok) { |
---|
| 1617 | + free(list); |
---|
1354 | 1618 | return -1; |
---|
| 1619 | + } |
---|
1355 | 1620 | *listp = list; |
---|
1356 | 1621 | return 0; |
---|
1357 | 1622 | } |
---|
.. | .. |
---|
1386 | 1651 | parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, |
---|
1387 | 1652 | struct parse_events_state *parse_state) |
---|
1388 | 1653 | { |
---|
1389 | | - struct perf_evsel *evsel, *leader; |
---|
| 1654 | + struct evsel *evsel, *leader; |
---|
1390 | 1655 | uintptr_t *leaders; |
---|
1391 | 1656 | bool is_leader = true; |
---|
1392 | 1657 | int i, nr_pmu = 0, total_members, ret = 0; |
---|
1393 | 1658 | |
---|
1394 | | - leader = list_first_entry(list, struct perf_evsel, node); |
---|
1395 | | - 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); |
---|
1396 | 1661 | total_members = evsel->idx - leader->idx + 1; |
---|
1397 | 1662 | |
---|
1398 | 1663 | leaders = calloc(total_members, sizeof(uintptr_t)); |
---|
.. | .. |
---|
1453 | 1718 | __evlist__for_each_entry(list, evsel) { |
---|
1454 | 1719 | if (i >= nr_pmu) |
---|
1455 | 1720 | i = 0; |
---|
1456 | | - evsel->leader = (struct perf_evsel *) leaders[i++]; |
---|
| 1721 | + evsel->leader = (struct evsel *) leaders[i++]; |
---|
1457 | 1722 | } |
---|
1458 | 1723 | |
---|
1459 | 1724 | /* The number of members and group name are same for each group */ |
---|
1460 | 1725 | for (i = 0; i < nr_pmu; i++) { |
---|
1461 | | - evsel = (struct perf_evsel *) leaders[i]; |
---|
1462 | | - evsel->nr_members = total_members / nr_pmu; |
---|
| 1726 | + evsel = (struct evsel *) leaders[i]; |
---|
| 1727 | + evsel->core.nr_members = total_members / nr_pmu; |
---|
1463 | 1728 | evsel->group_name = name ? strdup(name) : NULL; |
---|
1464 | 1729 | } |
---|
1465 | 1730 | |
---|
.. | .. |
---|
1476 | 1741 | void parse_events__set_leader(char *name, struct list_head *list, |
---|
1477 | 1742 | struct parse_events_state *parse_state) |
---|
1478 | 1743 | { |
---|
1479 | | - struct perf_evsel *leader; |
---|
| 1744 | + struct evsel *leader; |
---|
1480 | 1745 | |
---|
1481 | 1746 | if (list_empty(list)) { |
---|
1482 | 1747 | WARN_ONCE(true, "WARNING: failed to set leader: empty list"); |
---|
.. | .. |
---|
1487 | 1752 | return; |
---|
1488 | 1753 | |
---|
1489 | 1754 | __perf_evlist__set_leader(list); |
---|
1490 | | - leader = list_entry(list->next, struct perf_evsel, node); |
---|
| 1755 | + leader = list_entry(list->next, struct evsel, core.node); |
---|
1491 | 1756 | leader->group_name = name ? strdup(name) : NULL; |
---|
1492 | 1757 | } |
---|
1493 | 1758 | |
---|
.. | .. |
---|
1517 | 1782 | int sample_read; |
---|
1518 | 1783 | int pinned; |
---|
1519 | 1784 | int weak; |
---|
| 1785 | + int exclusive; |
---|
1520 | 1786 | }; |
---|
1521 | 1787 | |
---|
1522 | 1788 | static int get_event_modifier(struct event_modifier *mod, char *str, |
---|
1523 | | - struct perf_evsel *evsel) |
---|
| 1789 | + struct evsel *evsel) |
---|
1524 | 1790 | { |
---|
1525 | | - int eu = evsel ? evsel->attr.exclude_user : 0; |
---|
1526 | | - int ek = evsel ? evsel->attr.exclude_kernel : 0; |
---|
1527 | | - int eh = evsel ? evsel->attr.exclude_hv : 0; |
---|
1528 | | - int eH = evsel ? evsel->attr.exclude_host : 0; |
---|
1529 | | - int eG = evsel ? evsel->attr.exclude_guest : 0; |
---|
1530 | | - int eI = evsel ? evsel->attr.exclude_idle : 0; |
---|
1531 | | - 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; |
---|
1532 | 1798 | int precise_max = 0; |
---|
1533 | 1799 | int sample_read = 0; |
---|
1534 | | - 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; |
---|
1535 | 1802 | |
---|
1536 | 1803 | int exclude = eu | ek | eh; |
---|
1537 | 1804 | int exclude_GH = evsel ? evsel->exclude_GH : 0; |
---|
.. | .. |
---|
1543 | 1810 | if (*str == 'u') { |
---|
1544 | 1811 | if (!exclude) |
---|
1545 | 1812 | exclude = eu = ek = eh = 1; |
---|
| 1813 | + if (!exclude_GH && !perf_guest) |
---|
| 1814 | + eG = 1; |
---|
1546 | 1815 | eu = 0; |
---|
1547 | 1816 | } else if (*str == 'k') { |
---|
1548 | 1817 | if (!exclude) |
---|
.. | .. |
---|
1573 | 1842 | sample_read = 1; |
---|
1574 | 1843 | } else if (*str == 'D') { |
---|
1575 | 1844 | pinned = 1; |
---|
| 1845 | + } else if (*str == 'e') { |
---|
| 1846 | + exclusive = 1; |
---|
1576 | 1847 | } else if (*str == 'W') { |
---|
1577 | 1848 | weak = 1; |
---|
1578 | 1849 | } else |
---|
.. | .. |
---|
1606 | 1877 | mod->sample_read = sample_read; |
---|
1607 | 1878 | mod->pinned = pinned; |
---|
1608 | 1879 | mod->weak = weak; |
---|
| 1880 | + mod->exclusive = exclusive; |
---|
1609 | 1881 | |
---|
1610 | 1882 | return 0; |
---|
1611 | 1883 | } |
---|
.. | .. |
---|
1619 | 1891 | char *p = str; |
---|
1620 | 1892 | |
---|
1621 | 1893 | /* The sizeof includes 0 byte as well. */ |
---|
1622 | | - if (strlen(str) > (sizeof("ukhGHpppPSDIW") - 1)) |
---|
| 1894 | + if (strlen(str) > (sizeof("ukhGHpppPSDIWe") - 1)) |
---|
1623 | 1895 | return -1; |
---|
1624 | 1896 | |
---|
1625 | 1897 | while (*p) { |
---|
.. | .. |
---|
1633 | 1905 | |
---|
1634 | 1906 | int parse_events__modifier_event(struct list_head *list, char *str, bool add) |
---|
1635 | 1907 | { |
---|
1636 | | - struct perf_evsel *evsel; |
---|
| 1908 | + struct evsel *evsel; |
---|
1637 | 1909 | struct event_modifier mod; |
---|
1638 | 1910 | |
---|
1639 | 1911 | if (str == NULL) |
---|
.. | .. |
---|
1649 | 1921 | if (add && get_event_modifier(&mod, str, evsel)) |
---|
1650 | 1922 | return -EINVAL; |
---|
1651 | 1923 | |
---|
1652 | | - evsel->attr.exclude_user = mod.eu; |
---|
1653 | | - evsel->attr.exclude_kernel = mod.ek; |
---|
1654 | | - evsel->attr.exclude_hv = mod.eh; |
---|
1655 | | - evsel->attr.precise_ip = mod.precise; |
---|
1656 | | - evsel->attr.exclude_host = mod.eH; |
---|
1657 | | - evsel->attr.exclude_guest = mod.eG; |
---|
1658 | | - 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; |
---|
1659 | 1931 | evsel->exclude_GH = mod.exclude_GH; |
---|
1660 | 1932 | evsel->sample_read = mod.sample_read; |
---|
1661 | 1933 | evsel->precise_max = mod.precise_max; |
---|
1662 | 1934 | evsel->weak_group = mod.weak; |
---|
1663 | 1935 | |
---|
1664 | | - if (perf_evsel__is_group_leader(evsel)) |
---|
1665 | | - 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 | + } |
---|
1666 | 1940 | } |
---|
1667 | 1941 | |
---|
1668 | 1942 | return 0; |
---|
.. | .. |
---|
1670 | 1944 | |
---|
1671 | 1945 | int parse_events_name(struct list_head *list, char *name) |
---|
1672 | 1946 | { |
---|
1673 | | - struct perf_evsel *evsel; |
---|
| 1947 | + struct evsel *evsel; |
---|
1674 | 1948 | |
---|
1675 | 1949 | __evlist__for_each_entry(list, evsel) { |
---|
1676 | 1950 | if (!evsel->name) |
---|
.. | .. |
---|
1768 | 2042 | perf_pmu__parse_cleanup(); |
---|
1769 | 2043 | } |
---|
1770 | 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 | + |
---|
1771 | 2071 | enum perf_pmu_event_symbol_type |
---|
1772 | 2072 | perf_pmu__parse_check(const char *name) |
---|
1773 | 2073 | { |
---|
.. | .. |
---|
1792 | 2092 | return r ? r->type : PMU_EVENT_SYMBOL_ERR; |
---|
1793 | 2093 | } |
---|
1794 | 2094 | |
---|
1795 | | -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) |
---|
1796 | 2097 | { |
---|
1797 | 2098 | YY_BUFFER_STATE buffer; |
---|
1798 | 2099 | void *scanner; |
---|
1799 | 2100 | int ret; |
---|
1800 | 2101 | |
---|
1801 | | - ret = parse_events_lex_init_extra(start_token, &scanner); |
---|
| 2102 | + ret = parse_events_lex_init_extra(parse_state, &scanner); |
---|
1802 | 2103 | if (ret) |
---|
1803 | 2104 | return ret; |
---|
1804 | 2105 | |
---|
.. | .. |
---|
1806 | 2107 | |
---|
1807 | 2108 | #ifdef PARSER_DEBUG |
---|
1808 | 2109 | parse_events_debug = 1; |
---|
| 2110 | + parse_events_set_debug(1, scanner); |
---|
1809 | 2111 | #endif |
---|
1810 | 2112 | ret = parse_events_parse(parse_state, scanner); |
---|
1811 | 2113 | |
---|
.. | .. |
---|
1821 | 2123 | int parse_events_terms(struct list_head *terms, const char *str) |
---|
1822 | 2124 | { |
---|
1823 | 2125 | struct parse_events_state parse_state = { |
---|
1824 | | - .terms = NULL, |
---|
| 2126 | + .terms = NULL, |
---|
| 2127 | + .stoken = PE_START_TERMS, |
---|
1825 | 2128 | }; |
---|
1826 | 2129 | int ret; |
---|
1827 | 2130 | |
---|
1828 | | - ret = parse_events__scanner(str, &parse_state, PE_START_TERMS); |
---|
| 2131 | + ret = parse_events__scanner(str, &parse_state); |
---|
| 2132 | + perf_pmu__parse_cleanup(); |
---|
| 2133 | + |
---|
1829 | 2134 | if (!ret) { |
---|
1830 | 2135 | list_splice(parse_state.terms, terms); |
---|
1831 | 2136 | zfree(&parse_state.terms); |
---|
.. | .. |
---|
1836 | 2141 | return ret; |
---|
1837 | 2142 | } |
---|
1838 | 2143 | |
---|
1839 | | -int parse_events(struct perf_evlist *evlist, const char *str, |
---|
1840 | | - 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) |
---|
1841 | 2146 | { |
---|
1842 | 2147 | struct parse_events_state parse_state = { |
---|
1843 | | - .list = LIST_HEAD_INIT(parse_state.list), |
---|
1844 | | - .idx = evlist->nr_entries, |
---|
1845 | | - .error = err, |
---|
1846 | | - .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, |
---|
1847 | 2154 | }; |
---|
1848 | 2155 | int ret; |
---|
1849 | 2156 | |
---|
1850 | | - ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS); |
---|
| 2157 | + ret = parse_events__scanner(str, &parse_state); |
---|
1851 | 2158 | perf_pmu__parse_cleanup(); |
---|
1852 | 2159 | |
---|
1853 | 2160 | if (!ret && list_empty(&parse_state.list)) { |
---|
.. | .. |
---|
1861 | 2168 | perf_evlist__splice_list_tail(evlist, &parse_state.list); |
---|
1862 | 2169 | |
---|
1863 | 2170 | if (!ret) { |
---|
1864 | | - struct perf_evsel *last; |
---|
| 2171 | + struct evsel *last; |
---|
1865 | 2172 | |
---|
1866 | 2173 | evlist->nr_groups += parse_state.nr_groups; |
---|
1867 | | - last = perf_evlist__last(evlist); |
---|
| 2174 | + last = evlist__last(evlist); |
---|
1868 | 2175 | last->cmdline_group_boundary = true; |
---|
1869 | 2176 | |
---|
1870 | 2177 | return 0; |
---|
.. | .. |
---|
1872 | 2179 | |
---|
1873 | 2180 | /* |
---|
1874 | 2181 | * There are 2 users - builtin-record and builtin-test objects. |
---|
1875 | | - * Both call perf_evlist__delete in case of error, so we dont |
---|
| 2182 | + * Both call evlist__delete in case of error, so we dont |
---|
1876 | 2183 | * need to bother. |
---|
1877 | 2184 | */ |
---|
1878 | 2185 | return ret; |
---|
.. | .. |
---|
1887 | 2194 | return ws.ws_col > MAX_WIDTH ? MAX_WIDTH : ws.ws_col; |
---|
1888 | 2195 | } |
---|
1889 | 2196 | |
---|
1890 | | -void parse_events_print_error(struct parse_events_error *err, |
---|
1891 | | - 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) |
---|
1892 | 2199 | { |
---|
1893 | 2200 | const char *str = "invalid or unsupported event: "; |
---|
1894 | 2201 | char _buf[MAX_WIDTH]; |
---|
1895 | 2202 | char *buf = (char *) event; |
---|
1896 | 2203 | int idx = 0; |
---|
1897 | | - |
---|
1898 | | - if (err->str) { |
---|
| 2204 | + if (err_str) { |
---|
1899 | 2205 | /* -2 for extra '' in the final fprintf */ |
---|
1900 | 2206 | int width = get_term_width() - 2; |
---|
1901 | 2207 | int len_event = strlen(event); |
---|
.. | .. |
---|
1918 | 2224 | buf = _buf; |
---|
1919 | 2225 | |
---|
1920 | 2226 | /* We're cutting from the beginning. */ |
---|
1921 | | - if (err->idx > max_err_idx) |
---|
1922 | | - cut = err->idx - max_err_idx; |
---|
| 2227 | + if (err_idx > max_err_idx) |
---|
| 2228 | + cut = err_idx - max_err_idx; |
---|
1923 | 2229 | |
---|
1924 | 2230 | strncpy(buf, event + cut, max_len); |
---|
1925 | 2231 | |
---|
.. | .. |
---|
1932 | 2238 | buf[max_len] = 0; |
---|
1933 | 2239 | } |
---|
1934 | 2240 | |
---|
1935 | | - idx = len_str + err->idx - cut; |
---|
| 2241 | + idx = len_str + err_idx - cut; |
---|
1936 | 2242 | } |
---|
1937 | 2243 | |
---|
1938 | 2244 | fprintf(stderr, "%s'%s'\n", str, buf); |
---|
1939 | 2245 | if (idx) { |
---|
1940 | | - fprintf(stderr, "%*s\\___ %s\n", idx + 1, "", err->str); |
---|
1941 | | - if (err->help) |
---|
1942 | | - fprintf(stderr, "\n%s\n", err->help); |
---|
1943 | | - zfree(&err->str); |
---|
1944 | | - 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); |
---|
1945 | 2268 | } |
---|
1946 | 2269 | } |
---|
1947 | 2270 | |
---|
.. | .. |
---|
1950 | 2273 | int parse_events_option(const struct option *opt, const char *str, |
---|
1951 | 2274 | int unset __maybe_unused) |
---|
1952 | 2275 | { |
---|
1953 | | - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
---|
1954 | | - struct parse_events_error err = { .idx = 0, }; |
---|
1955 | | - 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); |
---|
1956 | 2282 | |
---|
1957 | 2283 | if (ret) { |
---|
1958 | 2284 | parse_events_print_error(&err, str); |
---|
.. | .. |
---|
1962 | 2288 | return ret; |
---|
1963 | 2289 | } |
---|
1964 | 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 | + |
---|
1965 | 2314 | static int |
---|
1966 | | -foreach_evsel_in_last_glob(struct perf_evlist *evlist, |
---|
1967 | | - int (*func)(struct perf_evsel *evsel, |
---|
| 2315 | +foreach_evsel_in_last_glob(struct evlist *evlist, |
---|
| 2316 | + int (*func)(struct evsel *evsel, |
---|
1968 | 2317 | const void *arg), |
---|
1969 | 2318 | const void *arg) |
---|
1970 | 2319 | { |
---|
1971 | | - struct perf_evsel *last = NULL; |
---|
| 2320 | + struct evsel *last = NULL; |
---|
1972 | 2321 | int err; |
---|
1973 | 2322 | |
---|
1974 | 2323 | /* |
---|
.. | .. |
---|
1977 | 2326 | * |
---|
1978 | 2327 | * So no need to WARN here, let *func do this. |
---|
1979 | 2328 | */ |
---|
1980 | | - if (evlist->nr_entries > 0) |
---|
1981 | | - last = perf_evlist__last(evlist); |
---|
| 2329 | + if (evlist->core.nr_entries > 0) |
---|
| 2330 | + last = evlist__last(evlist); |
---|
1982 | 2331 | |
---|
1983 | 2332 | do { |
---|
1984 | 2333 | err = (*func)(last, arg); |
---|
.. | .. |
---|
1987 | 2336 | if (!last) |
---|
1988 | 2337 | return 0; |
---|
1989 | 2338 | |
---|
1990 | | - if (last->node.prev == &evlist->entries) |
---|
| 2339 | + if (last->core.node.prev == &evlist->core.entries) |
---|
1991 | 2340 | return 0; |
---|
1992 | | - last = list_entry(last->node.prev, struct perf_evsel, node); |
---|
| 2341 | + last = list_entry(last->core.node.prev, struct evsel, core.node); |
---|
1993 | 2342 | } while (!last->cmdline_group_boundary); |
---|
1994 | 2343 | |
---|
1995 | 2344 | return 0; |
---|
1996 | 2345 | } |
---|
1997 | 2346 | |
---|
1998 | | -static int set_filter(struct perf_evsel *evsel, const void *arg) |
---|
| 2347 | +static int set_filter(struct evsel *evsel, const void *arg) |
---|
1999 | 2348 | { |
---|
2000 | 2349 | const char *str = arg; |
---|
2001 | 2350 | bool found = false; |
---|
.. | .. |
---|
2008 | 2357 | return -1; |
---|
2009 | 2358 | } |
---|
2010 | 2359 | |
---|
2011 | | - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { |
---|
2012 | | - 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) { |
---|
2013 | 2362 | fprintf(stderr, |
---|
2014 | 2363 | "not enough memory to hold filter string\n"); |
---|
2015 | 2364 | return -1; |
---|
.. | .. |
---|
2019 | 2368 | } |
---|
2020 | 2369 | |
---|
2021 | 2370 | while ((pmu = perf_pmu__scan(pmu)) != NULL) |
---|
2022 | | - if (pmu->type == evsel->attr.type) { |
---|
| 2371 | + if (pmu->type == evsel->core.attr.type) { |
---|
2023 | 2372 | found = true; |
---|
2024 | 2373 | break; |
---|
2025 | 2374 | } |
---|
.. | .. |
---|
2034 | 2383 | return -1; |
---|
2035 | 2384 | } |
---|
2036 | 2385 | |
---|
2037 | | - if (perf_evsel__append_addr_filter(evsel, str) < 0) { |
---|
| 2386 | + if (evsel__append_addr_filter(evsel, str) < 0) { |
---|
2038 | 2387 | fprintf(stderr, |
---|
2039 | 2388 | "not enough memory to hold filter string\n"); |
---|
2040 | 2389 | return -1; |
---|
.. | .. |
---|
2046 | 2395 | int parse_filter(const struct option *opt, const char *str, |
---|
2047 | 2396 | int unset __maybe_unused) |
---|
2048 | 2397 | { |
---|
2049 | | - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
---|
| 2398 | + struct evlist *evlist = *(struct evlist **)opt->value; |
---|
2050 | 2399 | |
---|
2051 | 2400 | return foreach_evsel_in_last_glob(evlist, set_filter, |
---|
2052 | 2401 | (const void *)str); |
---|
2053 | 2402 | } |
---|
2054 | 2403 | |
---|
2055 | | -static int add_exclude_perf_filter(struct perf_evsel *evsel, |
---|
| 2404 | +static int add_exclude_perf_filter(struct evsel *evsel, |
---|
2056 | 2405 | const void *arg __maybe_unused) |
---|
2057 | 2406 | { |
---|
2058 | 2407 | char new_filter[64]; |
---|
2059 | 2408 | |
---|
2060 | | - if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) { |
---|
| 2409 | + if (evsel == NULL || evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { |
---|
2061 | 2410 | fprintf(stderr, |
---|
2062 | 2411 | "--exclude-perf option should follow a -e tracepoint option\n"); |
---|
2063 | 2412 | return -1; |
---|
.. | .. |
---|
2065 | 2414 | |
---|
2066 | 2415 | snprintf(new_filter, sizeof(new_filter), "common_pid != %d", getpid()); |
---|
2067 | 2416 | |
---|
2068 | | - if (perf_evsel__append_tp_filter(evsel, new_filter) < 0) { |
---|
| 2417 | + if (evsel__append_tp_filter(evsel, new_filter) < 0) { |
---|
2069 | 2418 | fprintf(stderr, |
---|
2070 | 2419 | "not enough memory to hold filter string\n"); |
---|
2071 | 2420 | return -1; |
---|
.. | .. |
---|
2078 | 2427 | const char *arg __maybe_unused, |
---|
2079 | 2428 | int unset __maybe_unused) |
---|
2080 | 2429 | { |
---|
2081 | | - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
---|
| 2430 | + struct evlist *evlist = *(struct evlist **)opt->value; |
---|
2082 | 2431 | |
---|
2083 | 2432 | return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, |
---|
2084 | 2433 | NULL); |
---|
.. | .. |
---|
2244 | 2593 | { |
---|
2245 | 2594 | bool ret = true; |
---|
2246 | 2595 | int open_return; |
---|
2247 | | - struct perf_evsel *evsel; |
---|
| 2596 | + struct evsel *evsel; |
---|
2248 | 2597 | struct perf_event_attr attr = { |
---|
2249 | 2598 | .type = type, |
---|
2250 | 2599 | .config = config, |
---|
2251 | 2600 | .disabled = 1, |
---|
2252 | 2601 | }; |
---|
2253 | | - struct thread_map *tmap = thread_map__new_by_tid(0); |
---|
| 2602 | + struct perf_thread_map *tmap = thread_map__new_by_tid(0); |
---|
2254 | 2603 | |
---|
2255 | 2604 | if (tmap == NULL) |
---|
2256 | 2605 | return false; |
---|
2257 | 2606 | |
---|
2258 | | - evsel = perf_evsel__new(&attr); |
---|
| 2607 | + evsel = evsel__new(&attr); |
---|
2259 | 2608 | if (evsel) { |
---|
2260 | | - open_return = perf_evsel__open(evsel, NULL, tmap); |
---|
| 2609 | + open_return = evsel__open(evsel, NULL, tmap); |
---|
2261 | 2610 | ret = open_return >= 0; |
---|
2262 | 2611 | |
---|
2263 | 2612 | if (open_return == -EACCES) { |
---|
.. | .. |
---|
2268 | 2617 | * by default as some ARM machines do not support it. |
---|
2269 | 2618 | * |
---|
2270 | 2619 | */ |
---|
2271 | | - evsel->attr.exclude_kernel = 1; |
---|
2272 | | - ret = perf_evsel__open(evsel, NULL, tmap) >= 0; |
---|
| 2620 | + evsel->core.attr.exclude_kernel = 1; |
---|
| 2621 | + ret = evsel__open(evsel, NULL, tmap) >= 0; |
---|
2273 | 2622 | } |
---|
2274 | | - perf_evsel__delete(evsel); |
---|
| 2623 | + evsel__delete(evsel); |
---|
2275 | 2624 | } |
---|
2276 | 2625 | |
---|
2277 | | - thread_map__put(tmap); |
---|
| 2626 | + perf_thread_map__put(tmap); |
---|
2278 | 2627 | return ret; |
---|
2279 | 2628 | } |
---|
2280 | 2629 | |
---|
.. | .. |
---|
2375 | 2724 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { |
---|
2376 | 2725 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { |
---|
2377 | 2726 | /* skip invalid cache type */ |
---|
2378 | | - if (!perf_evsel__is_cache_op_valid(type, op)) |
---|
| 2727 | + if (!evsel__is_cache_op_valid(type, op)) |
---|
2379 | 2728 | continue; |
---|
2380 | 2729 | |
---|
2381 | 2730 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
---|
2382 | | - __perf_evsel__hw_cache_type_op_res_name(type, op, i, |
---|
2383 | | - name, sizeof(name)); |
---|
| 2731 | + __evsel__hw_cache_type_op_res_name(type, op, i, name, sizeof(name)); |
---|
2384 | 2732 | if (event_glob != NULL && !strglobmatch(name, event_glob)) |
---|
2385 | 2733 | continue; |
---|
2386 | 2734 | |
---|
.. | .. |
---|
2430 | 2778 | if (evt_list) |
---|
2431 | 2779 | goto out_free; |
---|
2432 | 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"); |
---|
2433 | 2800 | } |
---|
2434 | 2801 | |
---|
2435 | 2802 | void print_symbol_events(const char *event_glob, unsigned type, |
---|
.. | .. |
---|
2508 | 2875 | * Print the help text for the event symbols: |
---|
2509 | 2876 | */ |
---|
2510 | 2877 | void print_events(const char *event_glob, bool name_only, bool quiet_flag, |
---|
2511 | | - bool long_desc, bool details_flag) |
---|
| 2878 | + bool long_desc, bool details_flag, bool deprecated) |
---|
2512 | 2879 | { |
---|
2513 | 2880 | print_symbol_events(event_glob, PERF_TYPE_HARDWARE, |
---|
2514 | 2881 | event_symbols_hw, PERF_COUNT_HW_MAX, name_only); |
---|
2515 | 2882 | |
---|
2516 | 2883 | print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, |
---|
2517 | 2884 | event_symbols_sw, PERF_COUNT_SW_MAX, name_only); |
---|
| 2885 | + print_tool_events(event_glob, name_only); |
---|
2518 | 2886 | |
---|
2519 | 2887 | print_hwcache_events(event_glob, name_only); |
---|
2520 | 2888 | |
---|
2521 | 2889 | print_pmu_events(event_glob, name_only, quiet_flag, long_desc, |
---|
2522 | | - details_flag); |
---|
| 2890 | + details_flag, deprecated); |
---|
2523 | 2891 | |
---|
2524 | 2892 | if (event_glob != NULL) |
---|
2525 | 2893 | return; |
---|
.. | .. |
---|
2545 | 2913 | |
---|
2546 | 2914 | print_sdt_events(NULL, NULL, name_only); |
---|
2547 | 2915 | |
---|
2548 | | - 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); |
---|
2549 | 2919 | } |
---|
2550 | 2920 | |
---|
2551 | 2921 | int parse_events__is_hardcoded_term(struct parse_events_term *term) |
---|
.. | .. |
---|
2625 | 2995 | char *config, unsigned idx) |
---|
2626 | 2996 | { |
---|
2627 | 2997 | struct event_symbol *sym; |
---|
| 2998 | + char *str; |
---|
2628 | 2999 | struct parse_events_term temp = { |
---|
2629 | 3000 | .type_val = PARSE_EVENTS__TERM_TYPE_STR, |
---|
2630 | 3001 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, |
---|
2631 | | - .config = config ?: (char *) "event", |
---|
| 3002 | + .config = config, |
---|
2632 | 3003 | }; |
---|
2633 | 3004 | |
---|
| 3005 | + if (!temp.config) { |
---|
| 3006 | + temp.config = strdup("event"); |
---|
| 3007 | + if (!temp.config) |
---|
| 3008 | + return -ENOMEM; |
---|
| 3009 | + } |
---|
2634 | 3010 | BUG_ON(idx >= PERF_COUNT_HW_MAX); |
---|
2635 | 3011 | sym = &event_symbols_hw[idx]; |
---|
2636 | 3012 | |
---|
2637 | | - return new_term(term, &temp, (char *) sym->symbol, 0); |
---|
| 3013 | + str = strdup(sym->symbol); |
---|
| 3014 | + if (!str) |
---|
| 3015 | + return -ENOMEM; |
---|
| 3016 | + return new_term(term, &temp, str, 0); |
---|
2638 | 3017 | } |
---|
2639 | 3018 | |
---|
2640 | 3019 | int parse_events_term__clone(struct parse_events_term **new, |
---|
2641 | 3020 | struct parse_events_term *term) |
---|
2642 | 3021 | { |
---|
| 3022 | + char *str; |
---|
2643 | 3023 | struct parse_events_term temp = { |
---|
2644 | 3024 | .type_val = term->type_val, |
---|
2645 | 3025 | .type_term = term->type_term, |
---|
2646 | | - .config = term->config, |
---|
| 3026 | + .config = NULL, |
---|
2647 | 3027 | .err_term = term->err_term, |
---|
2648 | 3028 | .err_val = term->err_val, |
---|
2649 | 3029 | }; |
---|
2650 | 3030 | |
---|
2651 | | - return new_term(new, &temp, term->val.str, term->val.num); |
---|
| 3031 | + if (term->config) { |
---|
| 3032 | + temp.config = strdup(term->config); |
---|
| 3033 | + if (!temp.config) |
---|
| 3034 | + return -ENOMEM; |
---|
| 3035 | + } |
---|
| 3036 | + if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) |
---|
| 3037 | + return new_term(new, &temp, NULL, term->val.num); |
---|
| 3038 | + |
---|
| 3039 | + str = strdup(term->val.str); |
---|
| 3040 | + if (!str) |
---|
| 3041 | + return -ENOMEM; |
---|
| 3042 | + return new_term(new, &temp, str, 0); |
---|
| 3043 | +} |
---|
| 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); |
---|
2652 | 3055 | } |
---|
2653 | 3056 | |
---|
2654 | 3057 | int parse_events_copy_term_list(struct list_head *old, |
---|
.. | .. |
---|
2681 | 3084 | struct parse_events_term *term, *h; |
---|
2682 | 3085 | |
---|
2683 | 3086 | list_for_each_entry_safe(term, h, terms, list) { |
---|
2684 | | - if (term->array.nr_ranges) |
---|
2685 | | - zfree(&term->array.ranges); |
---|
2686 | 3087 | list_del_init(&term->list); |
---|
2687 | | - free(term); |
---|
| 3088 | + parse_events_term__delete(term); |
---|
2688 | 3089 | } |
---|
2689 | 3090 | } |
---|
2690 | 3091 | |
---|
.. | .. |
---|
2704 | 3105 | void parse_events_evlist_error(struct parse_events_state *parse_state, |
---|
2705 | 3106 | int idx, const char *str) |
---|
2706 | 3107 | { |
---|
2707 | | - struct parse_events_error *err = parse_state->error; |
---|
2708 | | - |
---|
2709 | | - if (!err) |
---|
| 3108 | + if (!parse_state->error) |
---|
2710 | 3109 | return; |
---|
2711 | | - err->idx = idx; |
---|
2712 | | - err->str = strdup(str); |
---|
2713 | | - WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); |
---|
| 3110 | + |
---|
| 3111 | + parse_events__handle_error(parse_state->error, idx, strdup(str), NULL); |
---|
2714 | 3112 | } |
---|
2715 | 3113 | |
---|
2716 | 3114 | static void config_terms_list(char *buf, size_t buf_sz) |
---|