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 /tools | |
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>
Diffstat (limited to 'tools')
-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)) { |