.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * auxtrace.c: AUX area trace support |
---|
3 | 4 | * Copyright (c) 2013-2015, Intel Corporation. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify it |
---|
6 | | - * under the terms and conditions of the GNU General Public License, |
---|
7 | | - * version 2, as published by the Free Software Foundation. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
---|
10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
12 | | - * more details. |
---|
13 | | - * |
---|
14 | 5 | */ |
---|
15 | 6 | |
---|
16 | 7 | #include <inttypes.h> |
---|
.. | .. |
---|
27 | 18 | #include <linux/bitops.h> |
---|
28 | 19 | #include <linux/log2.h> |
---|
29 | 20 | #include <linux/string.h> |
---|
| 21 | +#include <linux/time64.h> |
---|
30 | 22 | |
---|
31 | 23 | #include <sys/param.h> |
---|
32 | 24 | #include <stdlib.h> |
---|
33 | 25 | #include <stdio.h> |
---|
34 | 26 | #include <linux/list.h> |
---|
| 27 | +#include <linux/zalloc.h> |
---|
35 | 28 | |
---|
36 | | -#include "../perf.h" |
---|
37 | | -#include "util.h" |
---|
38 | 29 | #include "evlist.h" |
---|
39 | 30 | #include "dso.h" |
---|
40 | 31 | #include "map.h" |
---|
41 | 32 | #include "pmu.h" |
---|
42 | 33 | #include "evsel.h" |
---|
43 | | -#include "cpumap.h" |
---|
| 34 | +#include "evsel_config.h" |
---|
| 35 | +#include "symbol.h" |
---|
| 36 | +#include "util/perf_api_probe.h" |
---|
| 37 | +#include "util/synthetic-events.h" |
---|
44 | 38 | #include "thread_map.h" |
---|
45 | 39 | #include "asm/bug.h" |
---|
46 | 40 | #include "auxtrace.h" |
---|
.. | .. |
---|
48 | 42 | #include <linux/hash.h> |
---|
49 | 43 | |
---|
50 | 44 | #include "event.h" |
---|
| 45 | +#include "record.h" |
---|
51 | 46 | #include "session.h" |
---|
52 | 47 | #include "debug.h" |
---|
53 | 48 | #include <subcmd/parse-options.h> |
---|
.. | .. |
---|
57 | 52 | #include "intel-bts.h" |
---|
58 | 53 | #include "arm-spe.h" |
---|
59 | 54 | #include "s390-cpumsf.h" |
---|
| 55 | +#include "util/mmap.h" |
---|
60 | 56 | |
---|
61 | | -#include "sane_ctype.h" |
---|
| 57 | +#include <linux/ctype.h> |
---|
62 | 58 | #include "symbol/kallsyms.h" |
---|
| 59 | +#include <internal/lib.h> |
---|
| 60 | + |
---|
| 61 | +/* |
---|
| 62 | + * Make a group from 'leader' to 'last', requiring that the events were not |
---|
| 63 | + * already grouped to a different leader. |
---|
| 64 | + */ |
---|
| 65 | +static int perf_evlist__regroup(struct evlist *evlist, |
---|
| 66 | + struct evsel *leader, |
---|
| 67 | + struct evsel *last) |
---|
| 68 | +{ |
---|
| 69 | + struct evsel *evsel; |
---|
| 70 | + bool grp; |
---|
| 71 | + |
---|
| 72 | + if (!evsel__is_group_leader(leader)) |
---|
| 73 | + return -EINVAL; |
---|
| 74 | + |
---|
| 75 | + grp = false; |
---|
| 76 | + evlist__for_each_entry(evlist, evsel) { |
---|
| 77 | + if (grp) { |
---|
| 78 | + if (!(evsel->leader == leader || |
---|
| 79 | + (evsel->leader == evsel && |
---|
| 80 | + evsel->core.nr_members <= 1))) |
---|
| 81 | + return -EINVAL; |
---|
| 82 | + } else if (evsel == leader) { |
---|
| 83 | + grp = true; |
---|
| 84 | + } |
---|
| 85 | + if (evsel == last) |
---|
| 86 | + break; |
---|
| 87 | + } |
---|
| 88 | + |
---|
| 89 | + grp = false; |
---|
| 90 | + evlist__for_each_entry(evlist, evsel) { |
---|
| 91 | + if (grp) { |
---|
| 92 | + if (evsel->leader != leader) { |
---|
| 93 | + evsel->leader = leader; |
---|
| 94 | + if (leader->core.nr_members < 1) |
---|
| 95 | + leader->core.nr_members = 1; |
---|
| 96 | + leader->core.nr_members += 1; |
---|
| 97 | + } |
---|
| 98 | + } else if (evsel == leader) { |
---|
| 99 | + grp = true; |
---|
| 100 | + } |
---|
| 101 | + if (evsel == last) |
---|
| 102 | + break; |
---|
| 103 | + } |
---|
| 104 | + |
---|
| 105 | + return 0; |
---|
| 106 | +} |
---|
63 | 107 | |
---|
64 | 108 | static bool auxtrace__dont_decode(struct perf_session *session) |
---|
65 | 109 | { |
---|
.. | .. |
---|
131 | 175 | } |
---|
132 | 176 | |
---|
133 | 177 | void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, |
---|
134 | | - struct perf_evlist *evlist, int idx, |
---|
| 178 | + struct evlist *evlist, int idx, |
---|
135 | 179 | bool per_cpu) |
---|
136 | 180 | { |
---|
137 | 181 | mp->idx = idx; |
---|
138 | 182 | |
---|
139 | 183 | if (per_cpu) { |
---|
140 | | - mp->cpu = evlist->cpus->map[idx]; |
---|
141 | | - if (evlist->threads) |
---|
142 | | - mp->tid = thread_map__pid(evlist->threads, 0); |
---|
| 184 | + mp->cpu = evlist->core.cpus->map[idx]; |
---|
| 185 | + if (evlist->core.threads) |
---|
| 186 | + mp->tid = perf_thread_map__pid(evlist->core.threads, 0); |
---|
143 | 187 | else |
---|
144 | 188 | mp->tid = -1; |
---|
145 | 189 | } else { |
---|
146 | 190 | mp->cpu = -1; |
---|
147 | | - mp->tid = thread_map__pid(evlist->threads, idx); |
---|
| 191 | + mp->tid = perf_thread_map__pid(evlist->core.threads, idx); |
---|
148 | 192 | } |
---|
149 | 193 | } |
---|
150 | 194 | |
---|
.. | .. |
---|
388 | 432 | return err; |
---|
389 | 433 | |
---|
390 | 434 | if (event->header.type == PERF_RECORD_AUXTRACE) { |
---|
391 | | - if (event->header.size < sizeof(struct auxtrace_event) || |
---|
| 435 | + if (event->header.size < sizeof(struct perf_record_auxtrace) || |
---|
392 | 436 | event->header.size != sz) { |
---|
393 | 437 | err = -EINVAL; |
---|
394 | 438 | goto out; |
---|
.. | .. |
---|
411 | 455 | |
---|
412 | 456 | buffer = list_entry(queues->queue_array[i].head.next, |
---|
413 | 457 | struct auxtrace_buffer, list); |
---|
414 | | - list_del(&buffer->list); |
---|
| 458 | + list_del_init(&buffer->list); |
---|
415 | 459 | auxtrace_buffer__free(buffer); |
---|
416 | 460 | } |
---|
417 | 461 | } |
---|
.. | .. |
---|
506 | 550 | } |
---|
507 | 551 | |
---|
508 | 552 | size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, |
---|
509 | | - struct perf_evlist *evlist) |
---|
| 553 | + struct evlist *evlist) |
---|
510 | 554 | { |
---|
511 | 555 | if (itr) |
---|
512 | 556 | return itr->info_priv_size(itr, evlist); |
---|
.. | .. |
---|
521 | 565 | |
---|
522 | 566 | int auxtrace_record__info_fill(struct auxtrace_record *itr, |
---|
523 | 567 | struct perf_session *session, |
---|
524 | | - struct auxtrace_info_event *auxtrace_info, |
---|
| 568 | + struct perf_record_auxtrace_info *auxtrace_info, |
---|
525 | 569 | size_t priv_size) |
---|
526 | 570 | { |
---|
527 | 571 | if (itr) |
---|
.. | .. |
---|
542 | 586 | return 0; |
---|
543 | 587 | } |
---|
544 | 588 | |
---|
545 | | -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) |
---|
| 589 | +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit) |
---|
546 | 590 | { |
---|
547 | | - if (itr && itr->snapshot_finish) |
---|
| 591 | + if (!on_exit && itr && itr->snapshot_finish) |
---|
548 | 592 | return itr->snapshot_finish(itr); |
---|
549 | 593 | return 0; |
---|
550 | 594 | } |
---|
.. | .. |
---|
559 | 603 | } |
---|
560 | 604 | |
---|
561 | 605 | int auxtrace_record__options(struct auxtrace_record *itr, |
---|
562 | | - struct perf_evlist *evlist, |
---|
| 606 | + struct evlist *evlist, |
---|
563 | 607 | struct record_opts *opts) |
---|
564 | 608 | { |
---|
565 | | - if (itr) |
---|
| 609 | + if (itr) { |
---|
| 610 | + itr->evlist = evlist; |
---|
566 | 611 | return itr->recording_options(itr, evlist, opts); |
---|
| 612 | + } |
---|
567 | 613 | return 0; |
---|
568 | 614 | } |
---|
569 | 615 | |
---|
.. | .. |
---|
580 | 626 | if (!str) |
---|
581 | 627 | return 0; |
---|
582 | 628 | |
---|
583 | | - if (itr) |
---|
| 629 | + /* PMU-agnostic options */ |
---|
| 630 | + switch (*str) { |
---|
| 631 | + case 'e': |
---|
| 632 | + opts->auxtrace_snapshot_on_exit = true; |
---|
| 633 | + str++; |
---|
| 634 | + break; |
---|
| 635 | + default: |
---|
| 636 | + break; |
---|
| 637 | + } |
---|
| 638 | + |
---|
| 639 | + if (itr && itr->parse_snapshot_options) |
---|
584 | 640 | return itr->parse_snapshot_options(itr, opts, str); |
---|
585 | 641 | |
---|
586 | 642 | pr_err("No AUX area tracing to snapshot\n"); |
---|
587 | 643 | return -EINVAL; |
---|
588 | 644 | } |
---|
589 | 645 | |
---|
| 646 | +int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx) |
---|
| 647 | +{ |
---|
| 648 | + struct evsel *evsel; |
---|
| 649 | + |
---|
| 650 | + if (!itr->evlist || !itr->pmu) |
---|
| 651 | + return -EINVAL; |
---|
| 652 | + |
---|
| 653 | + evlist__for_each_entry(itr->evlist, evsel) { |
---|
| 654 | + if (evsel->core.attr.type == itr->pmu->type) { |
---|
| 655 | + if (evsel->disabled) |
---|
| 656 | + return 0; |
---|
| 657 | + return perf_evlist__enable_event_idx(itr->evlist, evsel, |
---|
| 658 | + idx); |
---|
| 659 | + } |
---|
| 660 | + } |
---|
| 661 | + return -EINVAL; |
---|
| 662 | +} |
---|
| 663 | + |
---|
| 664 | +/* |
---|
| 665 | + * Event record size is 16-bit which results in a maximum size of about 64KiB. |
---|
| 666 | + * Allow about 4KiB for the rest of the sample record, to give a maximum |
---|
| 667 | + * AUX area sample size of 60KiB. |
---|
| 668 | + */ |
---|
| 669 | +#define MAX_AUX_SAMPLE_SIZE (60 * 1024) |
---|
| 670 | + |
---|
| 671 | +/* Arbitrary default size if no other default provided */ |
---|
| 672 | +#define DEFAULT_AUX_SAMPLE_SIZE (4 * 1024) |
---|
| 673 | + |
---|
| 674 | +static int auxtrace_validate_aux_sample_size(struct evlist *evlist, |
---|
| 675 | + struct record_opts *opts) |
---|
| 676 | +{ |
---|
| 677 | + struct evsel *evsel; |
---|
| 678 | + bool has_aux_leader = false; |
---|
| 679 | + u32 sz; |
---|
| 680 | + |
---|
| 681 | + evlist__for_each_entry(evlist, evsel) { |
---|
| 682 | + sz = evsel->core.attr.aux_sample_size; |
---|
| 683 | + if (evsel__is_group_leader(evsel)) { |
---|
| 684 | + has_aux_leader = evsel__is_aux_event(evsel); |
---|
| 685 | + if (sz) { |
---|
| 686 | + if (has_aux_leader) |
---|
| 687 | + pr_err("Cannot add AUX area sampling to an AUX area event\n"); |
---|
| 688 | + else |
---|
| 689 | + pr_err("Cannot add AUX area sampling to a group leader\n"); |
---|
| 690 | + return -EINVAL; |
---|
| 691 | + } |
---|
| 692 | + } |
---|
| 693 | + if (sz > MAX_AUX_SAMPLE_SIZE) { |
---|
| 694 | + pr_err("AUX area sample size %u too big, max. %d\n", |
---|
| 695 | + sz, MAX_AUX_SAMPLE_SIZE); |
---|
| 696 | + return -EINVAL; |
---|
| 697 | + } |
---|
| 698 | + if (sz) { |
---|
| 699 | + if (!has_aux_leader) { |
---|
| 700 | + pr_err("Cannot add AUX area sampling because group leader is not an AUX area event\n"); |
---|
| 701 | + return -EINVAL; |
---|
| 702 | + } |
---|
| 703 | + evsel__set_sample_bit(evsel, AUX); |
---|
| 704 | + opts->auxtrace_sample_mode = true; |
---|
| 705 | + } else { |
---|
| 706 | + evsel__reset_sample_bit(evsel, AUX); |
---|
| 707 | + } |
---|
| 708 | + } |
---|
| 709 | + |
---|
| 710 | + if (!opts->auxtrace_sample_mode) { |
---|
| 711 | + pr_err("AUX area sampling requires an AUX area event group leader plus other events to which to add samples\n"); |
---|
| 712 | + return -EINVAL; |
---|
| 713 | + } |
---|
| 714 | + |
---|
| 715 | + if (!perf_can_aux_sample()) { |
---|
| 716 | + pr_err("AUX area sampling is not supported by kernel\n"); |
---|
| 717 | + return -EINVAL; |
---|
| 718 | + } |
---|
| 719 | + |
---|
| 720 | + return 0; |
---|
| 721 | +} |
---|
| 722 | + |
---|
| 723 | +int auxtrace_parse_sample_options(struct auxtrace_record *itr, |
---|
| 724 | + struct evlist *evlist, |
---|
| 725 | + struct record_opts *opts, const char *str) |
---|
| 726 | +{ |
---|
| 727 | + struct evsel_config_term *term; |
---|
| 728 | + struct evsel *aux_evsel; |
---|
| 729 | + bool has_aux_sample_size = false; |
---|
| 730 | + bool has_aux_leader = false; |
---|
| 731 | + struct evsel *evsel; |
---|
| 732 | + char *endptr; |
---|
| 733 | + unsigned long sz; |
---|
| 734 | + |
---|
| 735 | + if (!str) |
---|
| 736 | + goto no_opt; |
---|
| 737 | + |
---|
| 738 | + if (!itr) { |
---|
| 739 | + pr_err("No AUX area event to sample\n"); |
---|
| 740 | + return -EINVAL; |
---|
| 741 | + } |
---|
| 742 | + |
---|
| 743 | + sz = strtoul(str, &endptr, 0); |
---|
| 744 | + if (*endptr || sz > UINT_MAX) { |
---|
| 745 | + pr_err("Bad AUX area sampling option: '%s'\n", str); |
---|
| 746 | + return -EINVAL; |
---|
| 747 | + } |
---|
| 748 | + |
---|
| 749 | + if (!sz) |
---|
| 750 | + sz = itr->default_aux_sample_size; |
---|
| 751 | + |
---|
| 752 | + if (!sz) |
---|
| 753 | + sz = DEFAULT_AUX_SAMPLE_SIZE; |
---|
| 754 | + |
---|
| 755 | + /* Set aux_sample_size based on --aux-sample option */ |
---|
| 756 | + evlist__for_each_entry(evlist, evsel) { |
---|
| 757 | + if (evsel__is_group_leader(evsel)) { |
---|
| 758 | + has_aux_leader = evsel__is_aux_event(evsel); |
---|
| 759 | + } else if (has_aux_leader) { |
---|
| 760 | + evsel->core.attr.aux_sample_size = sz; |
---|
| 761 | + } |
---|
| 762 | + } |
---|
| 763 | +no_opt: |
---|
| 764 | + aux_evsel = NULL; |
---|
| 765 | + /* Override with aux_sample_size from config term */ |
---|
| 766 | + evlist__for_each_entry(evlist, evsel) { |
---|
| 767 | + if (evsel__is_aux_event(evsel)) |
---|
| 768 | + aux_evsel = evsel; |
---|
| 769 | + term = evsel__get_config_term(evsel, AUX_SAMPLE_SIZE); |
---|
| 770 | + if (term) { |
---|
| 771 | + has_aux_sample_size = true; |
---|
| 772 | + evsel->core.attr.aux_sample_size = term->val.aux_sample_size; |
---|
| 773 | + /* If possible, group with the AUX event */ |
---|
| 774 | + if (aux_evsel && evsel->core.attr.aux_sample_size) |
---|
| 775 | + perf_evlist__regroup(evlist, aux_evsel, evsel); |
---|
| 776 | + } |
---|
| 777 | + } |
---|
| 778 | + |
---|
| 779 | + if (!str && !has_aux_sample_size) |
---|
| 780 | + return 0; |
---|
| 781 | + |
---|
| 782 | + if (!itr) { |
---|
| 783 | + pr_err("No AUX area event to sample\n"); |
---|
| 784 | + return -EINVAL; |
---|
| 785 | + } |
---|
| 786 | + |
---|
| 787 | + return auxtrace_validate_aux_sample_size(evlist, opts); |
---|
| 788 | +} |
---|
| 789 | + |
---|
590 | 790 | struct auxtrace_record *__weak |
---|
591 | | -auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) |
---|
| 791 | +auxtrace_record__init(struct evlist *evlist __maybe_unused, int *err) |
---|
592 | 792 | { |
---|
593 | 793 | *err = 0; |
---|
594 | 794 | return NULL; |
---|
.. | .. |
---|
615 | 815 | struct auxtrace_index *auxtrace_index, *n; |
---|
616 | 816 | |
---|
617 | 817 | list_for_each_entry_safe(auxtrace_index, n, head, list) { |
---|
618 | | - list_del(&auxtrace_index->list); |
---|
| 818 | + list_del_init(&auxtrace_index->list); |
---|
619 | 819 | free(auxtrace_index); |
---|
620 | 820 | } |
---|
621 | 821 | } |
---|
.. | .. |
---|
801 | 1001 | } |
---|
802 | 1002 | } |
---|
803 | 1003 | |
---|
| 1004 | +struct auxtrace_queue *auxtrace_queues__sample_queue(struct auxtrace_queues *queues, |
---|
| 1005 | + struct perf_sample *sample, |
---|
| 1006 | + struct perf_session *session) |
---|
| 1007 | +{ |
---|
| 1008 | + struct perf_sample_id *sid; |
---|
| 1009 | + unsigned int idx; |
---|
| 1010 | + u64 id; |
---|
| 1011 | + |
---|
| 1012 | + id = sample->id; |
---|
| 1013 | + if (!id) |
---|
| 1014 | + return NULL; |
---|
| 1015 | + |
---|
| 1016 | + sid = perf_evlist__id2sid(session->evlist, id); |
---|
| 1017 | + if (!sid) |
---|
| 1018 | + return NULL; |
---|
| 1019 | + |
---|
| 1020 | + idx = sid->idx; |
---|
| 1021 | + |
---|
| 1022 | + if (idx >= queues->nr_queues) |
---|
| 1023 | + return NULL; |
---|
| 1024 | + |
---|
| 1025 | + return &queues->queue_array[idx]; |
---|
| 1026 | +} |
---|
| 1027 | + |
---|
| 1028 | +int auxtrace_queues__add_sample(struct auxtrace_queues *queues, |
---|
| 1029 | + struct perf_session *session, |
---|
| 1030 | + struct perf_sample *sample, u64 data_offset, |
---|
| 1031 | + u64 reference) |
---|
| 1032 | +{ |
---|
| 1033 | + struct auxtrace_buffer buffer = { |
---|
| 1034 | + .pid = -1, |
---|
| 1035 | + .data_offset = data_offset, |
---|
| 1036 | + .reference = reference, |
---|
| 1037 | + .size = sample->aux_sample.size, |
---|
| 1038 | + }; |
---|
| 1039 | + struct perf_sample_id *sid; |
---|
| 1040 | + u64 id = sample->id; |
---|
| 1041 | + unsigned int idx; |
---|
| 1042 | + |
---|
| 1043 | + if (!id) |
---|
| 1044 | + return -EINVAL; |
---|
| 1045 | + |
---|
| 1046 | + sid = perf_evlist__id2sid(session->evlist, id); |
---|
| 1047 | + if (!sid) |
---|
| 1048 | + return -ENOENT; |
---|
| 1049 | + |
---|
| 1050 | + idx = sid->idx; |
---|
| 1051 | + buffer.tid = sid->tid; |
---|
| 1052 | + buffer.cpu = sid->cpu; |
---|
| 1053 | + |
---|
| 1054 | + return auxtrace_queues__add_buffer(queues, session, idx, &buffer, NULL); |
---|
| 1055 | +} |
---|
| 1056 | + |
---|
| 1057 | +struct queue_data { |
---|
| 1058 | + bool samples; |
---|
| 1059 | + bool events; |
---|
| 1060 | +}; |
---|
| 1061 | + |
---|
| 1062 | +static int auxtrace_queue_data_cb(struct perf_session *session, |
---|
| 1063 | + union perf_event *event, u64 offset, |
---|
| 1064 | + void *data) |
---|
| 1065 | +{ |
---|
| 1066 | + struct queue_data *qd = data; |
---|
| 1067 | + struct perf_sample sample; |
---|
| 1068 | + int err; |
---|
| 1069 | + |
---|
| 1070 | + if (qd->events && event->header.type == PERF_RECORD_AUXTRACE) { |
---|
| 1071 | + if (event->header.size < sizeof(struct perf_record_auxtrace)) |
---|
| 1072 | + return -EINVAL; |
---|
| 1073 | + offset += event->header.size; |
---|
| 1074 | + return session->auxtrace->queue_data(session, NULL, event, |
---|
| 1075 | + offset); |
---|
| 1076 | + } |
---|
| 1077 | + |
---|
| 1078 | + if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE) |
---|
| 1079 | + return 0; |
---|
| 1080 | + |
---|
| 1081 | + err = perf_evlist__parse_sample(session->evlist, event, &sample); |
---|
| 1082 | + if (err) |
---|
| 1083 | + return err; |
---|
| 1084 | + |
---|
| 1085 | + if (!sample.aux_sample.size) |
---|
| 1086 | + return 0; |
---|
| 1087 | + |
---|
| 1088 | + offset += sample.aux_sample.data - (void *)event; |
---|
| 1089 | + |
---|
| 1090 | + return session->auxtrace->queue_data(session, &sample, NULL, offset); |
---|
| 1091 | +} |
---|
| 1092 | + |
---|
| 1093 | +int auxtrace_queue_data(struct perf_session *session, bool samples, bool events) |
---|
| 1094 | +{ |
---|
| 1095 | + struct queue_data qd = { |
---|
| 1096 | + .samples = samples, |
---|
| 1097 | + .events = events, |
---|
| 1098 | + }; |
---|
| 1099 | + |
---|
| 1100 | + if (auxtrace__dont_decode(session)) |
---|
| 1101 | + return 0; |
---|
| 1102 | + |
---|
| 1103 | + if (!session->auxtrace || !session->auxtrace->queue_data) |
---|
| 1104 | + return -EINVAL; |
---|
| 1105 | + |
---|
| 1106 | + return perf_session__peek_events(session, session->header.data_offset, |
---|
| 1107 | + session->header.data_size, |
---|
| 1108 | + auxtrace_queue_data_cb, &qd); |
---|
| 1109 | +} |
---|
| 1110 | + |
---|
804 | 1111 | void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd) |
---|
805 | 1112 | { |
---|
806 | 1113 | size_t adj = buffer->data_offset & (page_size - 1); |
---|
.. | .. |
---|
851 | 1158 | free(buffer); |
---|
852 | 1159 | } |
---|
853 | 1160 | |
---|
854 | | -void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, |
---|
| 1161 | +void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type, |
---|
855 | 1162 | int code, int cpu, pid_t pid, pid_t tid, u64 ip, |
---|
856 | | - const char *msg) |
---|
| 1163 | + const char *msg, u64 timestamp) |
---|
857 | 1164 | { |
---|
858 | 1165 | size_t size; |
---|
859 | 1166 | |
---|
860 | | - memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event)); |
---|
| 1167 | + memset(auxtrace_error, 0, sizeof(struct perf_record_auxtrace_error)); |
---|
861 | 1168 | |
---|
862 | 1169 | auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; |
---|
863 | 1170 | auxtrace_error->type = type; |
---|
.. | .. |
---|
865 | 1172 | auxtrace_error->cpu = cpu; |
---|
866 | 1173 | auxtrace_error->pid = pid; |
---|
867 | 1174 | auxtrace_error->tid = tid; |
---|
| 1175 | + auxtrace_error->fmt = 1; |
---|
868 | 1176 | auxtrace_error->ip = ip; |
---|
| 1177 | + auxtrace_error->time = timestamp; |
---|
869 | 1178 | strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG); |
---|
870 | 1179 | |
---|
871 | 1180 | size = (void *)auxtrace_error->msg - (void *)auxtrace_error + |
---|
.. | .. |
---|
884 | 1193 | |
---|
885 | 1194 | pr_debug2("Synthesizing auxtrace information\n"); |
---|
886 | 1195 | priv_size = auxtrace_record__info_priv_size(itr, session->evlist); |
---|
887 | | - ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); |
---|
| 1196 | + ev = zalloc(sizeof(struct perf_record_auxtrace_info) + priv_size); |
---|
888 | 1197 | if (!ev) |
---|
889 | 1198 | return -ENOMEM; |
---|
890 | 1199 | |
---|
891 | 1200 | ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO; |
---|
892 | | - ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) + |
---|
| 1201 | + ev->auxtrace_info.header.size = sizeof(struct perf_record_auxtrace_info) + |
---|
893 | 1202 | priv_size; |
---|
894 | 1203 | err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info, |
---|
895 | 1204 | priv_size); |
---|
.. | .. |
---|
902 | 1211 | return err; |
---|
903 | 1212 | } |
---|
904 | 1213 | |
---|
905 | | -int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, |
---|
906 | | - union perf_event *event, |
---|
907 | | - struct perf_session *session) |
---|
| 1214 | +static void unleader_evsel(struct evlist *evlist, struct evsel *leader) |
---|
| 1215 | +{ |
---|
| 1216 | + struct evsel *new_leader = NULL; |
---|
| 1217 | + struct evsel *evsel; |
---|
| 1218 | + |
---|
| 1219 | + /* Find new leader for the group */ |
---|
| 1220 | + evlist__for_each_entry(evlist, evsel) { |
---|
| 1221 | + if (evsel->leader != leader || evsel == leader) |
---|
| 1222 | + continue; |
---|
| 1223 | + if (!new_leader) |
---|
| 1224 | + new_leader = evsel; |
---|
| 1225 | + evsel->leader = new_leader; |
---|
| 1226 | + } |
---|
| 1227 | + |
---|
| 1228 | + /* Update group information */ |
---|
| 1229 | + if (new_leader) { |
---|
| 1230 | + zfree(&new_leader->group_name); |
---|
| 1231 | + new_leader->group_name = leader->group_name; |
---|
| 1232 | + leader->group_name = NULL; |
---|
| 1233 | + |
---|
| 1234 | + new_leader->core.nr_members = leader->core.nr_members - 1; |
---|
| 1235 | + leader->core.nr_members = 1; |
---|
| 1236 | + } |
---|
| 1237 | +} |
---|
| 1238 | + |
---|
| 1239 | +static void unleader_auxtrace(struct perf_session *session) |
---|
| 1240 | +{ |
---|
| 1241 | + struct evsel *evsel; |
---|
| 1242 | + |
---|
| 1243 | + evlist__for_each_entry(session->evlist, evsel) { |
---|
| 1244 | + if (auxtrace__evsel_is_auxtrace(session, evsel) && |
---|
| 1245 | + evsel__is_group_leader(evsel)) { |
---|
| 1246 | + unleader_evsel(session->evlist, evsel); |
---|
| 1247 | + } |
---|
| 1248 | + } |
---|
| 1249 | +} |
---|
| 1250 | + |
---|
| 1251 | +int perf_event__process_auxtrace_info(struct perf_session *session, |
---|
| 1252 | + union perf_event *event) |
---|
908 | 1253 | { |
---|
909 | 1254 | enum auxtrace_type type = event->auxtrace_info.type; |
---|
| 1255 | + int err; |
---|
910 | 1256 | |
---|
911 | 1257 | if (dump_trace) |
---|
912 | 1258 | fprintf(stdout, " type: %u\n", type); |
---|
913 | 1259 | |
---|
914 | 1260 | switch (type) { |
---|
915 | 1261 | case PERF_AUXTRACE_INTEL_PT: |
---|
916 | | - return intel_pt_process_auxtrace_info(event, session); |
---|
| 1262 | + err = intel_pt_process_auxtrace_info(event, session); |
---|
| 1263 | + break; |
---|
917 | 1264 | case PERF_AUXTRACE_INTEL_BTS: |
---|
918 | | - return intel_bts_process_auxtrace_info(event, session); |
---|
| 1265 | + err = intel_bts_process_auxtrace_info(event, session); |
---|
| 1266 | + break; |
---|
919 | 1267 | case PERF_AUXTRACE_ARM_SPE: |
---|
920 | | - return arm_spe_process_auxtrace_info(event, session); |
---|
| 1268 | + err = arm_spe_process_auxtrace_info(event, session); |
---|
| 1269 | + break; |
---|
921 | 1270 | case PERF_AUXTRACE_CS_ETM: |
---|
922 | | - return cs_etm__process_auxtrace_info(event, session); |
---|
| 1271 | + err = cs_etm__process_auxtrace_info(event, session); |
---|
| 1272 | + break; |
---|
923 | 1273 | case PERF_AUXTRACE_S390_CPUMSF: |
---|
924 | | - return s390_cpumsf_process_auxtrace_info(event, session); |
---|
| 1274 | + err = s390_cpumsf_process_auxtrace_info(event, session); |
---|
| 1275 | + break; |
---|
925 | 1276 | case PERF_AUXTRACE_UNKNOWN: |
---|
926 | 1277 | default: |
---|
927 | 1278 | return -EINVAL; |
---|
928 | 1279 | } |
---|
| 1280 | + |
---|
| 1281 | + if (err) |
---|
| 1282 | + return err; |
---|
| 1283 | + |
---|
| 1284 | + unleader_auxtrace(session); |
---|
| 1285 | + |
---|
| 1286 | + return 0; |
---|
929 | 1287 | } |
---|
930 | 1288 | |
---|
931 | | -s64 perf_event__process_auxtrace(struct perf_tool *tool, |
---|
932 | | - union perf_event *event, |
---|
933 | | - struct perf_session *session) |
---|
| 1289 | +s64 perf_event__process_auxtrace(struct perf_session *session, |
---|
| 1290 | + union perf_event *event) |
---|
934 | 1291 | { |
---|
935 | 1292 | s64 err; |
---|
936 | 1293 | |
---|
937 | 1294 | if (dump_trace) |
---|
938 | | - fprintf(stdout, " size: %#"PRIx64" offset: %#"PRIx64" ref: %#"PRIx64" idx: %u tid: %d cpu: %d\n", |
---|
| 1295 | + fprintf(stdout, " size: %#"PRI_lx64" offset: %#"PRI_lx64" ref: %#"PRI_lx64" idx: %u tid: %d cpu: %d\n", |
---|
939 | 1296 | event->auxtrace.size, event->auxtrace.offset, |
---|
940 | 1297 | event->auxtrace.reference, event->auxtrace.idx, |
---|
941 | 1298 | event->auxtrace.tid, event->auxtrace.cpu); |
---|
.. | .. |
---|
946 | 1303 | if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE) |
---|
947 | 1304 | return -EINVAL; |
---|
948 | 1305 | |
---|
949 | | - err = session->auxtrace->process_auxtrace_event(session, event, tool); |
---|
| 1306 | + err = session->auxtrace->process_auxtrace_event(session, event, session->tool); |
---|
950 | 1307 | if (err < 0) |
---|
951 | 1308 | return err; |
---|
952 | 1309 | |
---|
.. | .. |
---|
960 | 1317 | #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 |
---|
961 | 1318 | #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 |
---|
962 | 1319 | |
---|
963 | | -void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) |
---|
| 1320 | +void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, |
---|
| 1321 | + bool no_sample) |
---|
964 | 1322 | { |
---|
965 | | - synth_opts->instructions = true; |
---|
966 | 1323 | synth_opts->branches = true; |
---|
967 | 1324 | synth_opts->transactions = true; |
---|
968 | 1325 | synth_opts->ptwrites = true; |
---|
969 | 1326 | synth_opts->pwr_events = true; |
---|
| 1327 | + synth_opts->other_events = true; |
---|
970 | 1328 | synth_opts->errors = true; |
---|
971 | | - synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; |
---|
972 | | - synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
---|
| 1329 | + synth_opts->flc = true; |
---|
| 1330 | + synth_opts->llc = true; |
---|
| 1331 | + synth_opts->tlb = true; |
---|
| 1332 | + synth_opts->remote_access = true; |
---|
| 1333 | + |
---|
| 1334 | + if (no_sample) { |
---|
| 1335 | + synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; |
---|
| 1336 | + synth_opts->period = 1; |
---|
| 1337 | + synth_opts->calls = true; |
---|
| 1338 | + } else { |
---|
| 1339 | + synth_opts->instructions = true; |
---|
| 1340 | + synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; |
---|
| 1341 | + synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
---|
| 1342 | + } |
---|
973 | 1343 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; |
---|
974 | 1344 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; |
---|
975 | 1345 | synth_opts->initial_skip = 0; |
---|
| 1346 | +} |
---|
| 1347 | + |
---|
| 1348 | +static int get_flag(const char **ptr, unsigned int *flags) |
---|
| 1349 | +{ |
---|
| 1350 | + while (1) { |
---|
| 1351 | + char c = **ptr; |
---|
| 1352 | + |
---|
| 1353 | + if (c >= 'a' && c <= 'z') { |
---|
| 1354 | + *flags |= 1 << (c - 'a'); |
---|
| 1355 | + ++*ptr; |
---|
| 1356 | + return 0; |
---|
| 1357 | + } else if (c == ' ') { |
---|
| 1358 | + ++*ptr; |
---|
| 1359 | + continue; |
---|
| 1360 | + } else { |
---|
| 1361 | + return -1; |
---|
| 1362 | + } |
---|
| 1363 | + } |
---|
| 1364 | +} |
---|
| 1365 | + |
---|
| 1366 | +static int get_flags(const char **ptr, unsigned int *plus_flags, unsigned int *minus_flags) |
---|
| 1367 | +{ |
---|
| 1368 | + while (1) { |
---|
| 1369 | + switch (**ptr) { |
---|
| 1370 | + case '+': |
---|
| 1371 | + ++*ptr; |
---|
| 1372 | + if (get_flag(ptr, plus_flags)) |
---|
| 1373 | + return -1; |
---|
| 1374 | + break; |
---|
| 1375 | + case '-': |
---|
| 1376 | + ++*ptr; |
---|
| 1377 | + if (get_flag(ptr, minus_flags)) |
---|
| 1378 | + return -1; |
---|
| 1379 | + break; |
---|
| 1380 | + case ' ': |
---|
| 1381 | + ++*ptr; |
---|
| 1382 | + break; |
---|
| 1383 | + default: |
---|
| 1384 | + return 0; |
---|
| 1385 | + } |
---|
| 1386 | + } |
---|
976 | 1387 | } |
---|
977 | 1388 | |
---|
978 | 1389 | /* |
---|
.. | .. |
---|
997 | 1408 | } |
---|
998 | 1409 | |
---|
999 | 1410 | if (!str) { |
---|
1000 | | - itrace_synth_opts__set_default(synth_opts); |
---|
| 1411 | + itrace_synth_opts__set_default(synth_opts, |
---|
| 1412 | + synth_opts->default_no_sample); |
---|
1001 | 1413 | return 0; |
---|
1002 | 1414 | } |
---|
1003 | 1415 | |
---|
.. | .. |
---|
1056 | 1468 | case 'p': |
---|
1057 | 1469 | synth_opts->pwr_events = true; |
---|
1058 | 1470 | break; |
---|
| 1471 | + case 'o': |
---|
| 1472 | + synth_opts->other_events = true; |
---|
| 1473 | + break; |
---|
1059 | 1474 | case 'e': |
---|
1060 | 1475 | synth_opts->errors = true; |
---|
| 1476 | + if (get_flags(&p, &synth_opts->error_plus_flags, |
---|
| 1477 | + &synth_opts->error_minus_flags)) |
---|
| 1478 | + goto out_err; |
---|
1061 | 1479 | break; |
---|
1062 | 1480 | case 'd': |
---|
1063 | 1481 | synth_opts->log = true; |
---|
| 1482 | + if (get_flags(&p, &synth_opts->log_plus_flags, |
---|
| 1483 | + &synth_opts->log_minus_flags)) |
---|
| 1484 | + goto out_err; |
---|
1064 | 1485 | break; |
---|
1065 | 1486 | case 'c': |
---|
1066 | 1487 | synth_opts->branches = true; |
---|
.. | .. |
---|
1070 | 1491 | synth_opts->branches = true; |
---|
1071 | 1492 | synth_opts->returns = true; |
---|
1072 | 1493 | break; |
---|
| 1494 | + case 'G': |
---|
1073 | 1495 | case 'g': |
---|
1074 | | - synth_opts->callchain = true; |
---|
| 1496 | + if (p[-1] == 'G') |
---|
| 1497 | + synth_opts->add_callchain = true; |
---|
| 1498 | + else |
---|
| 1499 | + synth_opts->callchain = true; |
---|
1075 | 1500 | synth_opts->callchain_sz = |
---|
1076 | 1501 | PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; |
---|
1077 | 1502 | while (*p == ' ' || *p == ',') |
---|
.. | .. |
---|
1086 | 1511 | synth_opts->callchain_sz = val; |
---|
1087 | 1512 | } |
---|
1088 | 1513 | break; |
---|
| 1514 | + case 'L': |
---|
1089 | 1515 | case 'l': |
---|
1090 | | - synth_opts->last_branch = true; |
---|
| 1516 | + if (p[-1] == 'L') |
---|
| 1517 | + synth_opts->add_last_branch = true; |
---|
| 1518 | + else |
---|
| 1519 | + synth_opts->last_branch = true; |
---|
1091 | 1520 | synth_opts->last_branch_sz = |
---|
1092 | 1521 | PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; |
---|
1093 | 1522 | while (*p == ' ' || *p == ',') |
---|
.. | .. |
---|
1108 | 1537 | if (p == endptr) |
---|
1109 | 1538 | goto out_err; |
---|
1110 | 1539 | p = endptr; |
---|
| 1540 | + break; |
---|
| 1541 | + case 'f': |
---|
| 1542 | + synth_opts->flc = true; |
---|
| 1543 | + break; |
---|
| 1544 | + case 'm': |
---|
| 1545 | + synth_opts->llc = true; |
---|
| 1546 | + break; |
---|
| 1547 | + case 't': |
---|
| 1548 | + synth_opts->tlb = true; |
---|
| 1549 | + break; |
---|
| 1550 | + case 'a': |
---|
| 1551 | + synth_opts->remote_access = true; |
---|
| 1552 | + break; |
---|
| 1553 | + case 'q': |
---|
| 1554 | + synth_opts->quick += 1; |
---|
1111 | 1555 | break; |
---|
1112 | 1556 | case ' ': |
---|
1113 | 1557 | case ',': |
---|
.. | .. |
---|
1149 | 1593 | |
---|
1150 | 1594 | size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) |
---|
1151 | 1595 | { |
---|
1152 | | - struct auxtrace_error_event *e = &event->auxtrace_error; |
---|
| 1596 | + struct perf_record_auxtrace_error *e = &event->auxtrace_error; |
---|
| 1597 | + unsigned long long nsecs = e->time; |
---|
| 1598 | + const char *msg = e->msg; |
---|
1153 | 1599 | int ret; |
---|
1154 | 1600 | |
---|
1155 | 1601 | ret = fprintf(fp, " %s error type %u", |
---|
1156 | 1602 | auxtrace_error_name(e->type), e->type); |
---|
1157 | | - ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n", |
---|
1158 | | - e->cpu, e->pid, e->tid, e->ip, e->code, e->msg); |
---|
| 1603 | + |
---|
| 1604 | + if (e->fmt && nsecs) { |
---|
| 1605 | + unsigned long secs = nsecs / NSEC_PER_SEC; |
---|
| 1606 | + |
---|
| 1607 | + nsecs -= secs * NSEC_PER_SEC; |
---|
| 1608 | + ret += fprintf(fp, " time %lu.%09llu", secs, nsecs); |
---|
| 1609 | + } else { |
---|
| 1610 | + ret += fprintf(fp, " time 0"); |
---|
| 1611 | + } |
---|
| 1612 | + |
---|
| 1613 | + if (!e->fmt) |
---|
| 1614 | + msg = (const char *)&e->time; |
---|
| 1615 | + |
---|
| 1616 | + ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %s\n", |
---|
| 1617 | + e->cpu, e->pid, e->tid, e->ip, e->code, msg); |
---|
1159 | 1618 | return ret; |
---|
1160 | 1619 | } |
---|
1161 | 1620 | |
---|
1162 | 1621 | void perf_session__auxtrace_error_inc(struct perf_session *session, |
---|
1163 | 1622 | union perf_event *event) |
---|
1164 | 1623 | { |
---|
1165 | | - struct auxtrace_error_event *e = &event->auxtrace_error; |
---|
| 1624 | + struct perf_record_auxtrace_error *e = &event->auxtrace_error; |
---|
1166 | 1625 | |
---|
1167 | 1626 | if (e->type < PERF_AUXTRACE_ERROR_MAX) |
---|
1168 | 1627 | session->evlist->stats.nr_auxtrace_errors[e->type] += 1; |
---|
.. | .. |
---|
1181 | 1640 | } |
---|
1182 | 1641 | } |
---|
1183 | 1642 | |
---|
1184 | | -int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused, |
---|
1185 | | - union perf_event *event, |
---|
1186 | | - struct perf_session *session) |
---|
| 1643 | +int perf_event__process_auxtrace_error(struct perf_session *session, |
---|
| 1644 | + union perf_event *event) |
---|
1187 | 1645 | { |
---|
1188 | 1646 | if (auxtrace__dont_decode(session)) |
---|
1189 | 1647 | return 0; |
---|
.. | .. |
---|
1192 | 1650 | return 0; |
---|
1193 | 1651 | } |
---|
1194 | 1652 | |
---|
1195 | | -static int __auxtrace_mmap__read(struct auxtrace_mmap *mm, |
---|
| 1653 | +static int __auxtrace_mmap__read(struct mmap *map, |
---|
1196 | 1654 | struct auxtrace_record *itr, |
---|
1197 | 1655 | struct perf_tool *tool, process_auxtrace_t fn, |
---|
1198 | 1656 | bool snapshot, size_t snapshot_size) |
---|
1199 | 1657 | { |
---|
| 1658 | + struct auxtrace_mmap *mm = &map->auxtrace_mmap; |
---|
1200 | 1659 | u64 head, old = mm->prev, offset, ref; |
---|
1201 | 1660 | unsigned char *data = mm->base; |
---|
1202 | 1661 | size_t size, head_off, old_off, len1, len2, padding; |
---|
.. | .. |
---|
1283 | 1742 | ev.auxtrace.tid = mm->tid; |
---|
1284 | 1743 | ev.auxtrace.cpu = mm->cpu; |
---|
1285 | 1744 | |
---|
1286 | | - if (fn(tool, &ev, data1, len1, data2, len2)) |
---|
| 1745 | + if (fn(tool, map, &ev, data1, len1, data2, len2)) |
---|
1287 | 1746 | return -1; |
---|
1288 | 1747 | |
---|
1289 | 1748 | mm->prev = head; |
---|
.. | .. |
---|
1302 | 1761 | return 1; |
---|
1303 | 1762 | } |
---|
1304 | 1763 | |
---|
1305 | | -int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, |
---|
| 1764 | +int auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr, |
---|
1306 | 1765 | struct perf_tool *tool, process_auxtrace_t fn) |
---|
1307 | 1766 | { |
---|
1308 | | - return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0); |
---|
| 1767 | + return __auxtrace_mmap__read(map, itr, tool, fn, false, 0); |
---|
1309 | 1768 | } |
---|
1310 | 1769 | |
---|
1311 | | -int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm, |
---|
| 1770 | +int auxtrace_mmap__read_snapshot(struct mmap *map, |
---|
1312 | 1771 | struct auxtrace_record *itr, |
---|
1313 | 1772 | struct perf_tool *tool, process_auxtrace_t fn, |
---|
1314 | 1773 | size_t snapshot_size) |
---|
1315 | 1774 | { |
---|
1316 | | - return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size); |
---|
| 1775 | + return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size); |
---|
1317 | 1776 | } |
---|
1318 | 1777 | |
---|
1319 | 1778 | /** |
---|
.. | .. |
---|
1393 | 1852 | return; |
---|
1394 | 1853 | |
---|
1395 | 1854 | auxtrace_cache__drop(c); |
---|
1396 | | - free(c->hashtable); |
---|
| 1855 | + zfree(&c->hashtable); |
---|
1397 | 1856 | free(c); |
---|
1398 | 1857 | } |
---|
1399 | 1858 | |
---|
.. | .. |
---|
1420 | 1879 | return 0; |
---|
1421 | 1880 | } |
---|
1422 | 1881 | |
---|
| 1882 | +static struct auxtrace_cache_entry *auxtrace_cache__rm(struct auxtrace_cache *c, |
---|
| 1883 | + u32 key) |
---|
| 1884 | +{ |
---|
| 1885 | + struct auxtrace_cache_entry *entry; |
---|
| 1886 | + struct hlist_head *hlist; |
---|
| 1887 | + struct hlist_node *n; |
---|
| 1888 | + |
---|
| 1889 | + if (!c) |
---|
| 1890 | + return NULL; |
---|
| 1891 | + |
---|
| 1892 | + hlist = &c->hashtable[hash_32(key, c->bits)]; |
---|
| 1893 | + hlist_for_each_entry_safe(entry, n, hlist, hash) { |
---|
| 1894 | + if (entry->key == key) { |
---|
| 1895 | + hlist_del(&entry->hash); |
---|
| 1896 | + return entry; |
---|
| 1897 | + } |
---|
| 1898 | + } |
---|
| 1899 | + |
---|
| 1900 | + return NULL; |
---|
| 1901 | +} |
---|
| 1902 | + |
---|
| 1903 | +void auxtrace_cache__remove(struct auxtrace_cache *c, u32 key) |
---|
| 1904 | +{ |
---|
| 1905 | + struct auxtrace_cache_entry *entry = auxtrace_cache__rm(c, key); |
---|
| 1906 | + |
---|
| 1907 | + auxtrace_cache__free_entry(c, entry); |
---|
| 1908 | +} |
---|
| 1909 | + |
---|
1423 | 1910 | void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key) |
---|
1424 | 1911 | { |
---|
1425 | 1912 | struct auxtrace_cache_entry *entry; |
---|
.. | .. |
---|
1439 | 1926 | |
---|
1440 | 1927 | static void addr_filter__free_str(struct addr_filter *filt) |
---|
1441 | 1928 | { |
---|
1442 | | - free(filt->str); |
---|
| 1929 | + zfree(&filt->str); |
---|
1443 | 1930 | filt->action = NULL; |
---|
1444 | 1931 | filt->sym_from = NULL; |
---|
1445 | 1932 | filt->sym_to = NULL; |
---|
1446 | 1933 | filt->filename = NULL; |
---|
1447 | | - filt->str = NULL; |
---|
1448 | 1934 | } |
---|
1449 | 1935 | |
---|
1450 | 1936 | static struct addr_filter *addr_filter__new(void) |
---|
.. | .. |
---|
1678 | 2164 | bool near; |
---|
1679 | 2165 | }; |
---|
1680 | 2166 | |
---|
| 2167 | +static bool kern_sym_name_match(const char *kname, const char *name) |
---|
| 2168 | +{ |
---|
| 2169 | + size_t n = strlen(name); |
---|
| 2170 | + |
---|
| 2171 | + return !strcmp(kname, name) || |
---|
| 2172 | + (!strncmp(kname, name, n) && kname[n] == '\t'); |
---|
| 2173 | +} |
---|
| 2174 | + |
---|
1681 | 2175 | static bool kern_sym_match(struct sym_args *args, const char *name, char type) |
---|
1682 | 2176 | { |
---|
1683 | 2177 | /* A function with the same name, and global or the n'th found or any */ |
---|
1684 | 2178 | return kallsyms__is_function(type) && |
---|
1685 | | - !strcmp(name, args->name) && |
---|
| 2179 | + kern_sym_name_match(name, args->name) && |
---|
1686 | 2180 | ((args->global && isupper(type)) || |
---|
1687 | 2181 | (args->selected && ++(args->cnt) == args->idx) || |
---|
1688 | 2182 | (!args->global && !args->selected)); |
---|
.. | .. |
---|
1890 | 2384 | if (!map) |
---|
1891 | 2385 | return NULL; |
---|
1892 | 2386 | |
---|
1893 | | - map__load(map); |
---|
| 2387 | + if (map__load(map) < 0) |
---|
| 2388 | + pr_err("File '%s' not found or has no symbols.\n", name); |
---|
1894 | 2389 | |
---|
1895 | 2390 | dso = dso__get(map->dso); |
---|
1896 | 2391 | |
---|
.. | .. |
---|
1974 | 2469 | |
---|
1975 | 2470 | static int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso) |
---|
1976 | 2471 | { |
---|
1977 | | - struct symbol *first_sym = dso__first_symbol(dso); |
---|
1978 | | - struct symbol *last_sym = dso__last_symbol(dso); |
---|
1979 | | - |
---|
1980 | | - if (!first_sym || !last_sym) { |
---|
1981 | | - pr_err("Failed to determine filter for %s\nNo symbols found.\n", |
---|
| 2472 | + if (dso__data_file_size(dso, NULL)) { |
---|
| 2473 | + pr_err("Failed to determine filter for %s\nCannot determine file size.\n", |
---|
1982 | 2474 | filt->filename); |
---|
1983 | 2475 | return -EINVAL; |
---|
1984 | 2476 | } |
---|
1985 | 2477 | |
---|
1986 | | - filt->addr = first_sym->start; |
---|
1987 | | - filt->size = last_sym->end - first_sym->start; |
---|
| 2478 | + filt->addr = 0; |
---|
| 2479 | + filt->size = dso->data.file_size; |
---|
1988 | 2480 | |
---|
1989 | 2481 | return 0; |
---|
1990 | 2482 | } |
---|
.. | .. |
---|
2067 | 2559 | return err < 0 ? NULL : filter; |
---|
2068 | 2560 | } |
---|
2069 | 2561 | |
---|
2070 | | -static int parse_addr_filter(struct perf_evsel *evsel, const char *filter, |
---|
| 2562 | +static int parse_addr_filter(struct evsel *evsel, const char *filter, |
---|
2071 | 2563 | int max_nr) |
---|
2072 | 2564 | { |
---|
2073 | 2565 | struct addr_filters filts; |
---|
.. | .. |
---|
2100 | 2592 | goto out_exit; |
---|
2101 | 2593 | } |
---|
2102 | 2594 | |
---|
2103 | | - if (perf_evsel__append_addr_filter(evsel, new_filter)) { |
---|
| 2595 | + if (evsel__append_addr_filter(evsel, new_filter)) { |
---|
2104 | 2596 | err = -ENOMEM; |
---|
2105 | 2597 | goto out_exit; |
---|
2106 | 2598 | } |
---|
.. | .. |
---|
2118 | 2610 | return err; |
---|
2119 | 2611 | } |
---|
2120 | 2612 | |
---|
2121 | | -static struct perf_pmu *perf_evsel__find_pmu(struct perf_evsel *evsel) |
---|
| 2613 | +static int evsel__nr_addr_filter(struct evsel *evsel) |
---|
2122 | 2614 | { |
---|
2123 | | - struct perf_pmu *pmu = NULL; |
---|
2124 | | - |
---|
2125 | | - while ((pmu = perf_pmu__scan(pmu)) != NULL) { |
---|
2126 | | - if (pmu->type == evsel->attr.type) |
---|
2127 | | - break; |
---|
2128 | | - } |
---|
2129 | | - |
---|
2130 | | - return pmu; |
---|
2131 | | -} |
---|
2132 | | - |
---|
2133 | | -static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) |
---|
2134 | | -{ |
---|
2135 | | - struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); |
---|
| 2615 | + struct perf_pmu *pmu = evsel__find_pmu(evsel); |
---|
2136 | 2616 | int nr_addr_filters = 0; |
---|
2137 | 2617 | |
---|
2138 | 2618 | if (!pmu) |
---|
.. | .. |
---|
2143 | 2623 | return nr_addr_filters; |
---|
2144 | 2624 | } |
---|
2145 | 2625 | |
---|
2146 | | -int auxtrace_parse_filters(struct perf_evlist *evlist) |
---|
| 2626 | +int auxtrace_parse_filters(struct evlist *evlist) |
---|
2147 | 2627 | { |
---|
2148 | | - struct perf_evsel *evsel; |
---|
| 2628 | + struct evsel *evsel; |
---|
2149 | 2629 | char *filter; |
---|
2150 | 2630 | int err, max_nr; |
---|
2151 | 2631 | |
---|
2152 | 2632 | evlist__for_each_entry(evlist, evsel) { |
---|
2153 | 2633 | filter = evsel->filter; |
---|
2154 | | - max_nr = perf_evsel__nr_addr_filter(evsel); |
---|
| 2634 | + max_nr = evsel__nr_addr_filter(evsel); |
---|
2155 | 2635 | if (!filter || !max_nr) |
---|
2156 | 2636 | continue; |
---|
2157 | 2637 | evsel->filter = NULL; |
---|
.. | .. |
---|
2164 | 2644 | |
---|
2165 | 2645 | return 0; |
---|
2166 | 2646 | } |
---|
| 2647 | + |
---|
| 2648 | +int auxtrace__process_event(struct perf_session *session, union perf_event *event, |
---|
| 2649 | + struct perf_sample *sample, struct perf_tool *tool) |
---|
| 2650 | +{ |
---|
| 2651 | + if (!session->auxtrace) |
---|
| 2652 | + return 0; |
---|
| 2653 | + |
---|
| 2654 | + return session->auxtrace->process_event(session, event, sample, tool); |
---|
| 2655 | +} |
---|
| 2656 | + |
---|
| 2657 | +void auxtrace__dump_auxtrace_sample(struct perf_session *session, |
---|
| 2658 | + struct perf_sample *sample) |
---|
| 2659 | +{ |
---|
| 2660 | + if (!session->auxtrace || !session->auxtrace->dump_auxtrace_sample || |
---|
| 2661 | + auxtrace__dont_decode(session)) |
---|
| 2662 | + return; |
---|
| 2663 | + |
---|
| 2664 | + session->auxtrace->dump_auxtrace_sample(session, sample); |
---|
| 2665 | +} |
---|
| 2666 | + |
---|
| 2667 | +int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool) |
---|
| 2668 | +{ |
---|
| 2669 | + if (!session->auxtrace) |
---|
| 2670 | + return 0; |
---|
| 2671 | + |
---|
| 2672 | + return session->auxtrace->flush_events(session, tool); |
---|
| 2673 | +} |
---|
| 2674 | + |
---|
| 2675 | +void auxtrace__free_events(struct perf_session *session) |
---|
| 2676 | +{ |
---|
| 2677 | + if (!session->auxtrace) |
---|
| 2678 | + return; |
---|
| 2679 | + |
---|
| 2680 | + return session->auxtrace->free_events(session); |
---|
| 2681 | +} |
---|
| 2682 | + |
---|
| 2683 | +void auxtrace__free(struct perf_session *session) |
---|
| 2684 | +{ |
---|
| 2685 | + if (!session->auxtrace) |
---|
| 2686 | + return; |
---|
| 2687 | + |
---|
| 2688 | + return session->auxtrace->free(session); |
---|
| 2689 | +} |
---|
| 2690 | + |
---|
| 2691 | +bool auxtrace__evsel_is_auxtrace(struct perf_session *session, |
---|
| 2692 | + struct evsel *evsel) |
---|
| 2693 | +{ |
---|
| 2694 | + if (!session->auxtrace || !session->auxtrace->evsel_is_auxtrace) |
---|
| 2695 | + return false; |
---|
| 2696 | + |
---|
| 2697 | + return session->auxtrace->evsel_is_auxtrace(session, evsel); |
---|
| 2698 | +} |
---|