diff options
| author | Adrian Hunter <adrian.hunter@intel.com> | 2013-08-27 04:23:09 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-08-29 15:09:31 -0400 |
| commit | 75562573bab35b129cfd342fc2bcf89da84a6644 (patch) | |
| tree | b7dfa219d1a73560ce95639b7291f377645497ba | |
| parent | faf967068e8c4d8df52f01f9361241101b3065a0 (diff) | |
perf tools: Add support for PERF_SAMPLE_IDENTIFIER
Enable parsing of samples with sample format bit PERF_SAMPLE_IDENTIFIER.
In addition, if the kernel supports it, prefer it to selecting
PERF_SAMPLE_ID thereby allowing non-matching sample types.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1377591794-30553-8-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
| -rw-r--r-- | tools/perf/tests/mmap-basic.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/evlist.c | 111 | ||||
| -rw-r--r-- | tools/perf/util/evlist.h | 8 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 101 | ||||
| -rw-r--r-- | tools/perf/util/evsel.h | 14 | ||||
| -rw-r--r-- | tools/perf/util/record.c | 89 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 2 |
9 files changed, 310 insertions, 22 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 958a56a0e39e..9725aa375414 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -365,7 +365,7 @@ static int process_read_event(struct perf_tool *tool, | |||
| 365 | static int perf_report__setup_sample_type(struct perf_report *rep) | 365 | static int perf_report__setup_sample_type(struct perf_report *rep) |
| 366 | { | 366 | { |
| 367 | struct perf_session *self = rep->session; | 367 | struct perf_session *self = rep->session; |
| 368 | u64 sample_type = perf_evlist__sample_type(self->evlist); | 368 | u64 sample_type = perf_evlist__combined_sample_type(self->evlist); |
| 369 | 369 | ||
| 370 | if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { | 370 | if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
| 371 | if (sort__has_parent) { | 371 | if (sort__has_parent) { |
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 5b1b5aba722b..c4185b9aeb80 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
| @@ -72,7 +72,7 @@ int test__basic_mmap(void) | |||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | evsels[i]->attr.wakeup_events = 1; | 74 | evsels[i]->attr.wakeup_events = 1; |
| 75 | perf_evsel__set_sample_id(evsels[i]); | 75 | perf_evsel__set_sample_id(evsels[i], false); |
| 76 | 76 | ||
| 77 | perf_evlist__add(evlist, evsels[i]); | 77 | perf_evlist__add(evlist, evsels[i]); |
| 78 | 78 | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 19d911c011cd..491333910cf1 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -53,7 +53,8 @@ struct read_event { | |||
| 53 | (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ | 53 | (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ |
| 54 | PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ | 54 | PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ |
| 55 | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ | 55 | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ |
| 56 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) | 56 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \ |
| 57 | PERF_SAMPLE_IDENTIFIER) | ||
| 57 | 58 | ||
| 58 | struct sample_event { | 59 | struct sample_event { |
| 59 | struct perf_event_header header; | 60 | struct perf_event_header header; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 9d682e5f7184..6a629af51376 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -49,6 +49,21 @@ struct perf_evlist *perf_evlist__new(void) | |||
| 49 | return evlist; | 49 | return evlist; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /** | ||
| 53 | * perf_evlist__set_id_pos - set the positions of event ids. | ||
| 54 | * @evlist: selected event list | ||
| 55 | * | ||
| 56 | * Events with compatible sample types all have the same id_pos | ||
| 57 | * and is_pos. For convenience, put a copy on evlist. | ||
| 58 | */ | ||
| 59 | void perf_evlist__set_id_pos(struct perf_evlist *evlist) | ||
| 60 | { | ||
| 61 | struct perf_evsel *first = perf_evlist__first(evlist); | ||
| 62 | |||
| 63 | evlist->id_pos = first->id_pos; | ||
| 64 | evlist->is_pos = first->is_pos; | ||
| 65 | } | ||
| 66 | |||
| 52 | static void perf_evlist__purge(struct perf_evlist *evlist) | 67 | static void perf_evlist__purge(struct perf_evlist *evlist) |
| 53 | { | 68 | { |
| 54 | struct perf_evsel *pos, *n; | 69 | struct perf_evsel *pos, *n; |
| @@ -79,15 +94,20 @@ void perf_evlist__delete(struct perf_evlist *evlist) | |||
| 79 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) | 94 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) |
| 80 | { | 95 | { |
| 81 | list_add_tail(&entry->node, &evlist->entries); | 96 | list_add_tail(&entry->node, &evlist->entries); |
| 82 | ++evlist->nr_entries; | 97 | if (!evlist->nr_entries++) |
| 98 | perf_evlist__set_id_pos(evlist); | ||
| 83 | } | 99 | } |
| 84 | 100 | ||
| 85 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, | 101 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, |
| 86 | struct list_head *list, | 102 | struct list_head *list, |
| 87 | int nr_entries) | 103 | int nr_entries) |
| 88 | { | 104 | { |
| 105 | bool set_id_pos = !evlist->nr_entries; | ||
| 106 | |||
| 89 | list_splice_tail(list, &evlist->entries); | 107 | list_splice_tail(list, &evlist->entries); |
| 90 | evlist->nr_entries += nr_entries; | 108 | evlist->nr_entries += nr_entries; |
| 109 | if (set_id_pos) | ||
| 110 | perf_evlist__set_id_pos(evlist); | ||
| 91 | } | 111 | } |
| 92 | 112 | ||
| 93 | void __perf_evlist__set_leader(struct list_head *list) | 113 | void __perf_evlist__set_leader(struct list_head *list) |
| @@ -349,6 +369,55 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) | |||
| 349 | return NULL; | 369 | return NULL; |
| 350 | } | 370 | } |
| 351 | 371 | ||
| 372 | static int perf_evlist__event2id(struct perf_evlist *evlist, | ||
| 373 | union perf_event *event, u64 *id) | ||
| 374 | { | ||
| 375 | const u64 *array = event->sample.array; | ||
| 376 | ssize_t n; | ||
| 377 | |||
| 378 | n = (event->header.size - sizeof(event->header)) >> 3; | ||
| 379 | |||
| 380 | if (event->header.type == PERF_RECORD_SAMPLE) { | ||
| 381 | if (evlist->id_pos >= n) | ||
| 382 | return -1; | ||
| 383 | *id = array[evlist->id_pos]; | ||
| 384 | } else { | ||
| 385 | if (evlist->is_pos > n) | ||
| 386 | return -1; | ||
| 387 | n -= evlist->is_pos; | ||
| 388 | *id = array[n]; | ||
| 389 | } | ||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, | ||
| 394 | union perf_event *event) | ||
| 395 | { | ||
| 396 | struct hlist_head *head; | ||
| 397 | struct perf_sample_id *sid; | ||
| 398 | int hash; | ||
| 399 | u64 id; | ||
| 400 | |||
| 401 | if (evlist->nr_entries == 1) | ||
| 402 | return perf_evlist__first(evlist); | ||
| 403 | |||
| 404 | if (perf_evlist__event2id(evlist, event, &id)) | ||
| 405 | return NULL; | ||
| 406 | |||
| 407 | /* Synthesized events have an id of zero */ | ||
| 408 | if (!id) | ||
| 409 | return perf_evlist__first(evlist); | ||
| 410 | |||
| 411 | hash = hash_64(id, PERF_EVLIST__HLIST_BITS); | ||
| 412 | head = &evlist->heads[hash]; | ||
| 413 | |||
| 414 | hlist_for_each_entry(sid, head, node) { | ||
| 415 | if (sid->id == id) | ||
| 416 | return sid->evsel; | ||
| 417 | } | ||
| 418 | return NULL; | ||
| 419 | } | ||
| 420 | |||
| 352 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 421 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) |
| 353 | { | 422 | { |
| 354 | struct perf_mmap *md = &evlist->mmap[idx]; | 423 | struct perf_mmap *md = &evlist->mmap[idx]; |
| @@ -659,20 +728,40 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | |||
| 659 | 728 | ||
| 660 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) | 729 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) |
| 661 | { | 730 | { |
| 662 | struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; | 731 | struct perf_evsel *pos; |
| 663 | 732 | ||
| 664 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 733 | if (evlist->nr_entries == 1) |
| 665 | if (first->attr.sample_type != pos->attr.sample_type) | 734 | return true; |
| 735 | |||
| 736 | if (evlist->id_pos < 0 || evlist->is_pos < 0) | ||
| 737 | return false; | ||
| 738 | |||
| 739 | list_for_each_entry(pos, &evlist->entries, node) { | ||
| 740 | if (pos->id_pos != evlist->id_pos || | ||
| 741 | pos->is_pos != evlist->is_pos) | ||
| 666 | return false; | 742 | return false; |
| 667 | } | 743 | } |
| 668 | 744 | ||
| 669 | return true; | 745 | return true; |
| 670 | } | 746 | } |
| 671 | 747 | ||
| 672 | u64 perf_evlist__sample_type(struct perf_evlist *evlist) | 748 | u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) |
| 673 | { | 749 | { |
| 674 | struct perf_evsel *first = perf_evlist__first(evlist); | 750 | struct perf_evsel *evsel; |
| 675 | return first->attr.sample_type; | 751 | |
| 752 | if (evlist->combined_sample_type) | ||
| 753 | return evlist->combined_sample_type; | ||
| 754 | |||
| 755 | list_for_each_entry(evsel, &evlist->entries, node) | ||
| 756 | evlist->combined_sample_type |= evsel->attr.sample_type; | ||
| 757 | |||
| 758 | return evlist->combined_sample_type; | ||
| 759 | } | ||
| 760 | |||
| 761 | u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist) | ||
| 762 | { | ||
| 763 | evlist->combined_sample_type = 0; | ||
| 764 | return __perf_evlist__combined_sample_type(evlist); | ||
| 676 | } | 765 | } |
| 677 | 766 | ||
| 678 | bool perf_evlist__valid_read_format(struct perf_evlist *evlist) | 767 | bool perf_evlist__valid_read_format(struct perf_evlist *evlist) |
| @@ -727,6 +816,9 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) | |||
| 727 | 816 | ||
| 728 | if (sample_type & PERF_SAMPLE_CPU) | 817 | if (sample_type & PERF_SAMPLE_CPU) |
| 729 | size += sizeof(data->cpu) * 2; | 818 | size += sizeof(data->cpu) * 2; |
| 819 | |||
| 820 | if (sample_type & PERF_SAMPLE_IDENTIFIER) | ||
| 821 | size += sizeof(data->id); | ||
| 730 | out: | 822 | out: |
| 731 | return size; | 823 | return size; |
| 732 | } | 824 | } |
| @@ -885,7 +977,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) | |||
| 885 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, | 977 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, |
| 886 | struct perf_sample *sample) | 978 | struct perf_sample *sample) |
| 887 | { | 979 | { |
| 888 | struct perf_evsel *evsel = perf_evlist__first(evlist); | 980 | struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); |
| 981 | |||
| 982 | if (!evsel) | ||
| 983 | return -EFAULT; | ||
| 889 | return perf_evsel__parse_sample(evsel, event, sample); | 984 | return perf_evsel__parse_sample(evsel, event, sample); |
| 890 | } | 985 | } |
| 891 | 986 | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 327ababa67b6..ab95d7273638 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -32,6 +32,9 @@ struct perf_evlist { | |||
| 32 | int nr_fds; | 32 | int nr_fds; |
| 33 | int nr_mmaps; | 33 | int nr_mmaps; |
| 34 | int mmap_len; | 34 | int mmap_len; |
| 35 | int id_pos; | ||
| 36 | int is_pos; | ||
| 37 | u64 combined_sample_type; | ||
| 35 | struct { | 38 | struct { |
| 36 | int cork_fd; | 39 | int cork_fd; |
| 37 | pid_t pid; | 40 | pid_t pid; |
| @@ -85,6 +88,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | |||
| 85 | int perf_evlist__open(struct perf_evlist *evlist); | 88 | int perf_evlist__open(struct perf_evlist *evlist); |
| 86 | void perf_evlist__close(struct perf_evlist *evlist); | 89 | void perf_evlist__close(struct perf_evlist *evlist); |
| 87 | 90 | ||
| 91 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); | ||
| 92 | bool perf_can_sample_identifier(void); | ||
| 88 | void perf_evlist__config(struct perf_evlist *evlist, | 93 | void perf_evlist__config(struct perf_evlist *evlist, |
| 89 | struct perf_record_opts *opts); | 94 | struct perf_record_opts *opts); |
| 90 | 95 | ||
| @@ -121,7 +126,8 @@ void __perf_evlist__set_leader(struct list_head *list); | |||
| 121 | void perf_evlist__set_leader(struct perf_evlist *evlist); | 126 | void perf_evlist__set_leader(struct perf_evlist *evlist); |
| 122 | 127 | ||
| 123 | u64 perf_evlist__read_format(struct perf_evlist *evlist); | 128 | u64 perf_evlist__read_format(struct perf_evlist *evlist); |
| 124 | u64 perf_evlist__sample_type(struct perf_evlist *evlist); | 129 | u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist); |
| 130 | u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist); | ||
| 125 | bool perf_evlist__sample_id_all(struct perf_evlist *evlist); | 131 | bool perf_evlist__sample_id_all(struct perf_evlist *evlist); |
| 126 | u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); | 132 | u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); |
| 127 | 133 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7e328c47f3b6..db4e431cb6ca 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -31,7 +31,7 @@ static struct { | |||
| 31 | 31 | ||
| 32 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 32 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
| 33 | 33 | ||
| 34 | static int __perf_evsel__sample_size(u64 sample_type) | 34 | int __perf_evsel__sample_size(u64 sample_type) |
| 35 | { | 35 | { |
| 36 | u64 mask = sample_type & PERF_SAMPLE_MASK; | 36 | u64 mask = sample_type & PERF_SAMPLE_MASK; |
| 37 | int size = 0; | 37 | int size = 0; |
| @@ -47,6 +47,72 @@ static int __perf_evsel__sample_size(u64 sample_type) | |||
| 47 | return size; | 47 | return size; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | /** | ||
| 51 | * __perf_evsel__calc_id_pos - calculate id_pos. | ||
| 52 | * @sample_type: sample type | ||
| 53 | * | ||
| 54 | * This function returns the position of the event id (PERF_SAMPLE_ID or | ||
| 55 | * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct | ||
| 56 | * sample_event. | ||
| 57 | */ | ||
| 58 | static int __perf_evsel__calc_id_pos(u64 sample_type) | ||
| 59 | { | ||
| 60 | int idx = 0; | ||
| 61 | |||
| 62 | if (sample_type & PERF_SAMPLE_IDENTIFIER) | ||
| 63 | return 0; | ||
| 64 | |||
| 65 | if (!(sample_type & PERF_SAMPLE_ID)) | ||
| 66 | return -1; | ||
| 67 | |||
| 68 | if (sample_type & PERF_SAMPLE_IP) | ||
| 69 | idx += 1; | ||
| 70 | |||
| 71 | if (sample_type & PERF_SAMPLE_TID) | ||
| 72 | idx += 1; | ||
| 73 | |||
| 74 | if (sample_type & PERF_SAMPLE_TIME) | ||
| 75 | idx += 1; | ||
| 76 | |||
| 77 | if (sample_type & PERF_SAMPLE_ADDR) | ||
| 78 | idx += 1; | ||
| 79 | |||
| 80 | return idx; | ||
| 81 | } | ||
| 82 | |||
| 83 | /** | ||
| 84 | * __perf_evsel__calc_is_pos - calculate is_pos. | ||
| 85 | * @sample_type: sample type | ||
| 86 | * | ||
| 87 | * This function returns the position (counting backwards) of the event id | ||
| 88 | * (PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if | ||
| 89 | * sample_id_all is used there is an id sample appended to non-sample events. | ||
| 90 | */ | ||
| 91 | static int __perf_evsel__calc_is_pos(u64 sample_type) | ||
| 92 | { | ||
| 93 | int idx = 1; | ||
| 94 | |||
| 95 | if (sample_type & PERF_SAMPLE_IDENTIFIER) | ||
| 96 | return 1; | ||
| 97 | |||
| 98 | if (!(sample_type & PERF_SAMPLE_ID)) | ||
| 99 | return -1; | ||
| 100 | |||
| 101 | if (sample_type & PERF_SAMPLE_CPU) | ||
| 102 | idx += 1; | ||
| 103 | |||
| 104 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 105 | idx += 1; | ||
| 106 | |||
| 107 | return idx; | ||
| 108 | } | ||
| 109 | |||
| 110 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel) | ||
| 111 | { | ||
| 112 | evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type); | ||
| 113 | evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type); | ||
| 114 | } | ||
| 115 | |||
| 50 | void hists__init(struct hists *hists) | 116 | void hists__init(struct hists *hists) |
| 51 | { | 117 | { |
| 52 | memset(hists, 0, sizeof(*hists)); | 118 | memset(hists, 0, sizeof(*hists)); |
| @@ -63,6 +129,7 @@ void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | |||
| 63 | if (!(evsel->attr.sample_type & bit)) { | 129 | if (!(evsel->attr.sample_type & bit)) { |
| 64 | evsel->attr.sample_type |= bit; | 130 | evsel->attr.sample_type |= bit; |
| 65 | evsel->sample_size += sizeof(u64); | 131 | evsel->sample_size += sizeof(u64); |
| 132 | perf_evsel__calc_id_pos(evsel); | ||
| 66 | } | 133 | } |
| 67 | } | 134 | } |
| 68 | 135 | ||
| @@ -72,12 +139,19 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, | |||
| 72 | if (evsel->attr.sample_type & bit) { | 139 | if (evsel->attr.sample_type & bit) { |
| 73 | evsel->attr.sample_type &= ~bit; | 140 | evsel->attr.sample_type &= ~bit; |
| 74 | evsel->sample_size -= sizeof(u64); | 141 | evsel->sample_size -= sizeof(u64); |
| 142 | perf_evsel__calc_id_pos(evsel); | ||
| 75 | } | 143 | } |
| 76 | } | 144 | } |
| 77 | 145 | ||
| 78 | void perf_evsel__set_sample_id(struct perf_evsel *evsel) | 146 | void perf_evsel__set_sample_id(struct perf_evsel *evsel, |
| 147 | bool can_sample_identifier) | ||
| 79 | { | 148 | { |
| 80 | perf_evsel__set_sample_bit(evsel, ID); | 149 | if (can_sample_identifier) { |
| 150 | perf_evsel__reset_sample_bit(evsel, ID); | ||
| 151 | perf_evsel__set_sample_bit(evsel, IDENTIFIER); | ||
| 152 | } else { | ||
| 153 | perf_evsel__set_sample_bit(evsel, ID); | ||
| 154 | } | ||
| 81 | evsel->attr.read_format |= PERF_FORMAT_ID; | 155 | evsel->attr.read_format |= PERF_FORMAT_ID; |
| 82 | } | 156 | } |
| 83 | 157 | ||
| @@ -90,6 +164,7 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
| 90 | INIT_LIST_HEAD(&evsel->node); | 164 | INIT_LIST_HEAD(&evsel->node); |
| 91 | hists__init(&evsel->hists); | 165 | hists__init(&evsel->hists); |
| 92 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); | 166 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
| 167 | perf_evsel__calc_id_pos(evsel); | ||
| 93 | } | 168 | } |
| 94 | 169 | ||
| 95 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 170 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
| @@ -509,7 +584,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
| 509 | * We need ID even in case of single event, because | 584 | * We need ID even in case of single event, because |
| 510 | * PERF_SAMPLE_READ process ID specific data. | 585 | * PERF_SAMPLE_READ process ID specific data. |
| 511 | */ | 586 | */ |
| 512 | perf_evsel__set_sample_id(evsel); | 587 | perf_evsel__set_sample_id(evsel, false); |
| 513 | 588 | ||
| 514 | /* | 589 | /* |
| 515 | * Apply group format only if we belong to group | 590 | * Apply group format only if we belong to group |
| @@ -1088,6 +1163,11 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, | |||
| 1088 | array += ((event->header.size - | 1163 | array += ((event->header.size - |
| 1089 | sizeof(event->header)) / sizeof(u64)) - 1; | 1164 | sizeof(event->header)) / sizeof(u64)) - 1; |
| 1090 | 1165 | ||
| 1166 | if (type & PERF_SAMPLE_IDENTIFIER) { | ||
| 1167 | sample->id = *array; | ||
| 1168 | array--; | ||
| 1169 | } | ||
| 1170 | |||
| 1091 | if (type & PERF_SAMPLE_CPU) { | 1171 | if (type & PERF_SAMPLE_CPU) { |
| 1092 | u.val64 = *array; | 1172 | u.val64 = *array; |
| 1093 | if (swapped) { | 1173 | if (swapped) { |
| @@ -1184,6 +1264,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 1184 | if (evsel->sample_size + sizeof(event->header) > event->header.size) | 1264 | if (evsel->sample_size + sizeof(event->header) > event->header.size) |
| 1185 | return -EFAULT; | 1265 | return -EFAULT; |
| 1186 | 1266 | ||
| 1267 | data->id = -1ULL; | ||
| 1268 | if (type & PERF_SAMPLE_IDENTIFIER) { | ||
| 1269 | data->id = *array; | ||
| 1270 | array++; | ||
| 1271 | } | ||
| 1272 | |||
| 1187 | if (type & PERF_SAMPLE_IP) { | 1273 | if (type & PERF_SAMPLE_IP) { |
| 1188 | data->ip = *array; | 1274 | data->ip = *array; |
| 1189 | array++; | 1275 | array++; |
| @@ -1214,7 +1300,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 1214 | array++; | 1300 | array++; |
| 1215 | } | 1301 | } |
| 1216 | 1302 | ||
| 1217 | data->id = -1ULL; | ||
| 1218 | if (type & PERF_SAMPLE_ID) { | 1303 | if (type & PERF_SAMPLE_ID) { |
| 1219 | data->id = *array; | 1304 | data->id = *array; |
| 1220 | array++; | 1305 | array++; |
| @@ -1396,6 +1481,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
| 1396 | 1481 | ||
| 1397 | array = event->sample.array; | 1482 | array = event->sample.array; |
| 1398 | 1483 | ||
| 1484 | if (type & PERF_SAMPLE_IDENTIFIER) { | ||
| 1485 | *array = sample->id; | ||
| 1486 | array++; | ||
| 1487 | } | ||
| 1488 | |||
| 1399 | if (type & PERF_SAMPLE_IP) { | 1489 | if (type & PERF_SAMPLE_IP) { |
| 1400 | *array = sample->ip; | 1490 | *array = sample->ip; |
| 1401 | array++; | 1491 | array++; |
| @@ -1584,6 +1674,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value) | |||
| 1584 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), | 1674 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), |
| 1585 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), | 1675 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), |
| 1586 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), | 1676 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), |
| 1677 | bit_name(IDENTIFIER), | ||
| 1587 | { .name = NULL, } | 1678 | { .name = NULL, } |
| 1588 | }; | 1679 | }; |
| 1589 | #undef bit_name | 1680 | #undef bit_name |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 532a5f925da0..4a7bdc713bab 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -48,6 +48,12 @@ struct perf_sample_id { | |||
| 48 | * @name - Can be set to retain the original event name passed by the user, | 48 | * @name - Can be set to retain the original event name passed by the user, |
| 49 | * so that when showing results in tools such as 'perf stat', we | 49 | * so that when showing results in tools such as 'perf stat', we |
| 50 | * show the name used, not some alias. | 50 | * show the name used, not some alias. |
| 51 | * @id_pos: the position of the event id (PERF_SAMPLE_ID or | ||
| 52 | * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of | ||
| 53 | * struct sample_event | ||
| 54 | * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or | ||
| 55 | * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all | ||
| 56 | * is used there is an id sample appended to non-sample events | ||
| 51 | */ | 57 | */ |
| 52 | struct perf_evsel { | 58 | struct perf_evsel { |
| 53 | struct list_head node; | 59 | struct list_head node; |
| @@ -74,6 +80,8 @@ struct perf_evsel { | |||
| 74 | } handler; | 80 | } handler; |
| 75 | struct cpu_map *cpus; | 81 | struct cpu_map *cpus; |
| 76 | unsigned int sample_size; | 82 | unsigned int sample_size; |
| 83 | int id_pos; | ||
| 84 | int is_pos; | ||
| 77 | bool supported; | 85 | bool supported; |
| 78 | bool needs_swap; | 86 | bool needs_swap; |
| 79 | /* parse modifier helper */ | 87 | /* parse modifier helper */ |
| @@ -104,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel); | |||
| 104 | void perf_evsel__config(struct perf_evsel *evsel, | 112 | void perf_evsel__config(struct perf_evsel *evsel, |
| 105 | struct perf_record_opts *opts); | 113 | struct perf_record_opts *opts); |
| 106 | 114 | ||
| 115 | int __perf_evsel__sample_size(u64 sample_type); | ||
| 116 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); | ||
| 117 | |||
| 107 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); | 118 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); |
| 108 | 119 | ||
| 109 | #define PERF_EVSEL__MAX_ALIASES 8 | 120 | #define PERF_EVSEL__MAX_ALIASES 8 |
| @@ -142,7 +153,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, | |||
| 142 | #define perf_evsel__reset_sample_bit(evsel, bit) \ | 153 | #define perf_evsel__reset_sample_bit(evsel, bit) \ |
| 143 | __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) | 154 | __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) |
| 144 | 155 | ||
| 145 | void perf_evsel__set_sample_id(struct perf_evsel *evsel); | 156 | void perf_evsel__set_sample_id(struct perf_evsel *evsel, |
| 157 | bool use_sample_identifier); | ||
| 146 | 158 | ||
| 147 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, | 159 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, |
| 148 | const char *filter); | 160 | const char *filter); |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 9b5ef7933135..18d73aa2f0f8 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
| @@ -1,11 +1,83 @@ | |||
| 1 | #include "evlist.h" | 1 | #include "evlist.h" |
| 2 | #include "evsel.h" | 2 | #include "evsel.h" |
| 3 | #include "cpumap.h" | 3 | #include "cpumap.h" |
| 4 | #include "parse-events.h" | ||
| 5 | |||
| 6 | typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); | ||
| 7 | |||
| 8 | static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) | ||
| 9 | { | ||
| 10 | struct perf_evlist *evlist; | ||
| 11 | struct perf_evsel *evsel; | ||
| 12 | int err = -EAGAIN, fd; | ||
| 13 | |||
| 14 | evlist = perf_evlist__new(); | ||
| 15 | if (!evlist) | ||
| 16 | return -ENOMEM; | ||
| 17 | |||
| 18 | if (parse_events(evlist, str)) | ||
| 19 | goto out_delete; | ||
| 20 | |||
| 21 | evsel = perf_evlist__first(evlist); | ||
| 22 | |||
| 23 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
| 24 | if (fd < 0) | ||
| 25 | goto out_delete; | ||
| 26 | close(fd); | ||
| 27 | |||
| 28 | fn(evsel); | ||
| 29 | |||
| 30 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
| 31 | if (fd < 0) { | ||
| 32 | if (errno == EINVAL) | ||
| 33 | err = -EINVAL; | ||
| 34 | goto out_delete; | ||
| 35 | } | ||
| 36 | close(fd); | ||
| 37 | err = 0; | ||
| 38 | |||
| 39 | out_delete: | ||
| 40 | perf_evlist__delete(evlist); | ||
| 41 | return err; | ||
| 42 | } | ||
| 43 | |||
| 44 | static bool perf_probe_api(setup_probe_fn_t fn) | ||
| 45 | { | ||
| 46 | const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; | ||
| 47 | struct cpu_map *cpus; | ||
| 48 | int cpu, ret, i = 0; | ||
| 49 | |||
| 50 | cpus = cpu_map__new(NULL); | ||
| 51 | if (!cpus) | ||
| 52 | return false; | ||
| 53 | cpu = cpus->map[0]; | ||
| 54 | cpu_map__delete(cpus); | ||
| 55 | |||
| 56 | do { | ||
| 57 | ret = perf_do_probe_api(fn, cpu, try[i++]); | ||
| 58 | if (!ret) | ||
| 59 | return true; | ||
| 60 | } while (ret == -EAGAIN && try[i]); | ||
| 61 | |||
| 62 | return false; | ||
| 63 | } | ||
| 64 | |||
| 65 | static void perf_probe_sample_identifier(struct perf_evsel *evsel) | ||
| 66 | { | ||
| 67 | evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; | ||
| 68 | } | ||
| 69 | |||
| 70 | bool perf_can_sample_identifier(void) | ||
| 71 | { | ||
| 72 | return perf_probe_api(perf_probe_sample_identifier); | ||
| 73 | } | ||
| 4 | 74 | ||
| 5 | void perf_evlist__config(struct perf_evlist *evlist, | 75 | void perf_evlist__config(struct perf_evlist *evlist, |
| 6 | struct perf_record_opts *opts) | 76 | struct perf_record_opts *opts) |
| 7 | { | 77 | { |
| 8 | struct perf_evsel *evsel; | 78 | struct perf_evsel *evsel; |
| 79 | bool use_sample_identifier = false; | ||
| 80 | |||
| 9 | /* | 81 | /* |
| 10 | * Set the evsel leader links before we configure attributes, | 82 | * Set the evsel leader links before we configure attributes, |
| 11 | * since some might depend on this info. | 83 | * since some might depend on this info. |
| @@ -16,10 +88,21 @@ void perf_evlist__config(struct perf_evlist *evlist, | |||
| 16 | if (evlist->cpus->map[0] < 0) | 88 | if (evlist->cpus->map[0] < 0) |
| 17 | opts->no_inherit = true; | 89 | opts->no_inherit = true; |
| 18 | 90 | ||
| 19 | list_for_each_entry(evsel, &evlist->entries, node) { | 91 | list_for_each_entry(evsel, &evlist->entries, node) |
| 20 | perf_evsel__config(evsel, opts); | 92 | perf_evsel__config(evsel, opts); |
| 21 | 93 | ||
| 22 | if (evlist->nr_entries > 1) | 94 | if (evlist->nr_entries > 1) { |
| 23 | perf_evsel__set_sample_id(evsel); | 95 | struct perf_evsel *first = perf_evlist__first(evlist); |
| 96 | |||
| 97 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
| 98 | if (evsel->attr.sample_type == first->attr.sample_type) | ||
| 99 | continue; | ||
| 100 | use_sample_identifier = perf_can_sample_identifier(); | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | list_for_each_entry(evsel, &evlist->entries, node) | ||
| 104 | perf_evsel__set_sample_id(evsel, use_sample_identifier); | ||
| 24 | } | 105 | } |
| 106 | |||
| 107 | perf_evlist__set_id_pos(evlist); | ||
| 25 | } | 108 | } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c3ac483be48e..07642a7b9346 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -739,7 +739,7 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
| 739 | union perf_event *event, | 739 | union perf_event *event, |
| 740 | struct perf_sample *sample) | 740 | struct perf_sample *sample) |
| 741 | { | 741 | { |
| 742 | u64 sample_type = perf_evlist__sample_type(session->evlist); | 742 | u64 sample_type = __perf_evlist__combined_sample_type(session->evlist); |
| 743 | 743 | ||
| 744 | if (event->header.type != PERF_RECORD_SAMPLE && | 744 | if (event->header.type != PERF_RECORD_SAMPLE && |
| 745 | !perf_evlist__sample_id_all(session->evlist)) { | 745 | !perf_evlist__sample_id_all(session->evlist)) { |
