Commit 75562573bab35b129cfd342fc2bcf89da84a6644
Committed by
Arnaldo Carvalho de Melo
1 parent
faf967068e
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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>
Showing 9 changed files with 310 additions and 22 deletions Side-by-side Diff
tools/perf/builtin-report.c
... | ... | @@ -365,7 +365,7 @@ |
365 | 365 | static int perf_report__setup_sample_type(struct perf_report *rep) |
366 | 366 | { |
367 | 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 | 370 | if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
371 | 371 | if (sort__has_parent) { |
tools/perf/tests/mmap-basic.c
tools/perf/util/event.h
... | ... | @@ -53,7 +53,8 @@ |
53 | 53 | (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ |
54 | 54 | PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ |
55 | 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 | 59 | struct sample_event { |
59 | 60 | struct perf_event_header header; |
tools/perf/util/evlist.c
... | ... | @@ -49,6 +49,21 @@ |
49 | 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 | 67 | static void perf_evlist__purge(struct perf_evlist *evlist) |
53 | 68 | { |
54 | 69 | struct perf_evsel *pos, *n; |
55 | 70 | |
56 | 71 | |
... | ... | @@ -79,15 +94,20 @@ |
79 | 94 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) |
80 | 95 | { |
81 | 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 | 101 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, |
86 | 102 | struct list_head *list, |
87 | 103 | int nr_entries) |
88 | 104 | { |
105 | + bool set_id_pos = !evlist->nr_entries; | |
106 | + | |
89 | 107 | list_splice_tail(list, &evlist->entries); |
90 | 108 | evlist->nr_entries += nr_entries; |
109 | + if (set_id_pos) | |
110 | + perf_evlist__set_id_pos(evlist); | |
91 | 111 | } |
92 | 112 | |
93 | 113 | void __perf_evlist__set_leader(struct list_head *list) |
... | ... | @@ -349,6 +369,55 @@ |
349 | 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 | 421 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) |
353 | 422 | { |
354 | 423 | struct perf_mmap *md = &evlist->mmap[idx]; |
355 | 424 | |
356 | 425 | |
357 | 426 | |
358 | 427 | |
... | ... | @@ -659,22 +728,42 @@ |
659 | 728 | |
660 | 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) { | |
665 | - if (first->attr.sample_type != pos->attr.sample_type) | |
733 | + if (evlist->nr_entries == 1) | |
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 | 742 | return false; |
667 | 743 | } |
668 | 744 | |
669 | 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); | |
675 | - return first->attr.sample_type; | |
750 | + struct perf_evsel *evsel; | |
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; | |
676 | 759 | } |
677 | 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); | |
765 | +} | |
766 | + | |
678 | 767 | bool perf_evlist__valid_read_format(struct perf_evlist *evlist) |
679 | 768 | { |
680 | 769 | struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; |
... | ... | @@ -727,6 +816,9 @@ |
727 | 816 | |
728 | 817 | if (sample_type & PERF_SAMPLE_CPU) |
729 | 818 | size += sizeof(data->cpu) * 2; |
819 | + | |
820 | + if (sample_type & PERF_SAMPLE_IDENTIFIER) | |
821 | + size += sizeof(data->id); | |
730 | 822 | out: |
731 | 823 | return size; |
732 | 824 | } |
... | ... | @@ -885,7 +977,10 @@ |
885 | 977 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, |
886 | 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 | 984 | return perf_evsel__parse_sample(evsel, event, sample); |
890 | 985 | } |
891 | 986 |
tools/perf/util/evlist.h
... | ... | @@ -32,6 +32,9 @@ |
32 | 32 | int nr_fds; |
33 | 33 | int nr_mmaps; |
34 | 34 | int mmap_len; |
35 | + int id_pos; | |
36 | + int is_pos; | |
37 | + u64 combined_sample_type; | |
35 | 38 | struct { |
36 | 39 | int cork_fd; |
37 | 40 | pid_t pid; |
... | ... | @@ -85,6 +88,8 @@ |
85 | 88 | int perf_evlist__open(struct perf_evlist *evlist); |
86 | 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 | 93 | void perf_evlist__config(struct perf_evlist *evlist, |
89 | 94 | struct perf_record_opts *opts); |
90 | 95 | |
... | ... | @@ -121,7 +126,8 @@ |
121 | 126 | void perf_evlist__set_leader(struct perf_evlist *evlist); |
122 | 127 | |
123 | 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 | 131 | bool perf_evlist__sample_id_all(struct perf_evlist *evlist); |
126 | 132 | u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); |
127 | 133 |
tools/perf/util/evsel.c
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | |
32 | 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 | 36 | u64 mask = sample_type & PERF_SAMPLE_MASK; |
37 | 37 | int size = 0; |
... | ... | @@ -47,6 +47,72 @@ |
47 | 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 | 116 | void hists__init(struct hists *hists) |
51 | 117 | { |
52 | 118 | memset(hists, 0, sizeof(*hists)); |
... | ... | @@ -63,6 +129,7 @@ |
63 | 129 | if (!(evsel->attr.sample_type & bit)) { |
64 | 130 | evsel->attr.sample_type |= bit; |
65 | 131 | evsel->sample_size += sizeof(u64); |
132 | + perf_evsel__calc_id_pos(evsel); | |
66 | 133 | } |
67 | 134 | } |
68 | 135 | |
69 | 136 | |
70 | 137 | |
... | ... | @@ -72,12 +139,19 @@ |
72 | 139 | if (evsel->attr.sample_type & bit) { |
73 | 140 | evsel->attr.sample_type &= ~bit; |
74 | 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 | 155 | evsel->attr.read_format |= PERF_FORMAT_ID; |
82 | 156 | } |
83 | 157 | |
... | ... | @@ -90,6 +164,7 @@ |
90 | 164 | INIT_LIST_HEAD(&evsel->node); |
91 | 165 | hists__init(&evsel->hists); |
92 | 166 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
167 | + perf_evsel__calc_id_pos(evsel); | |
93 | 168 | } |
94 | 169 | |
95 | 170 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
... | ... | @@ -509,7 +584,7 @@ |
509 | 584 | * We need ID even in case of single event, because |
510 | 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 | 590 | * Apply group format only if we belong to group |
... | ... | @@ -1088,6 +1163,11 @@ |
1088 | 1163 | array += ((event->header.size - |
1089 | 1164 | sizeof(event->header)) / sizeof(u64)) - 1; |
1090 | 1165 | |
1166 | + if (type & PERF_SAMPLE_IDENTIFIER) { | |
1167 | + sample->id = *array; | |
1168 | + array--; | |
1169 | + } | |
1170 | + | |
1091 | 1171 | if (type & PERF_SAMPLE_CPU) { |
1092 | 1172 | u.val64 = *array; |
1093 | 1173 | if (swapped) { |
... | ... | @@ -1184,6 +1264,12 @@ |
1184 | 1264 | if (evsel->sample_size + sizeof(event->header) > event->header.size) |
1185 | 1265 | return -EFAULT; |
1186 | 1266 | |
1267 | + data->id = -1ULL; | |
1268 | + if (type & PERF_SAMPLE_IDENTIFIER) { | |
1269 | + data->id = *array; | |
1270 | + array++; | |
1271 | + } | |
1272 | + | |
1187 | 1273 | if (type & PERF_SAMPLE_IP) { |
1188 | 1274 | data->ip = *array; |
1189 | 1275 | array++; |
... | ... | @@ -1214,7 +1300,6 @@ |
1214 | 1300 | array++; |
1215 | 1301 | } |
1216 | 1302 | |
1217 | - data->id = -1ULL; | |
1218 | 1303 | if (type & PERF_SAMPLE_ID) { |
1219 | 1304 | data->id = *array; |
1220 | 1305 | array++; |
... | ... | @@ -1396,6 +1481,11 @@ |
1396 | 1481 | |
1397 | 1482 | array = event->sample.array; |
1398 | 1483 | |
1484 | + if (type & PERF_SAMPLE_IDENTIFIER) { | |
1485 | + *array = sample->id; | |
1486 | + array++; | |
1487 | + } | |
1488 | + | |
1399 | 1489 | if (type & PERF_SAMPLE_IP) { |
1400 | 1490 | *array = sample->ip; |
1401 | 1491 | array++; |
... | ... | @@ -1584,6 +1674,7 @@ |
1584 | 1674 | bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), |
1585 | 1675 | bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), |
1586 | 1676 | bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), |
1677 | + bit_name(IDENTIFIER), | |
1587 | 1678 | { .name = NULL, } |
1588 | 1679 | }; |
1589 | 1680 | #undef bit_name |
tools/perf/util/evsel.h
... | ... | @@ -48,6 +48,12 @@ |
48 | 48 | * @name - Can be set to retain the original event name passed by the user, |
49 | 49 | * so that when showing results in tools such as 'perf stat', we |
50 | 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 | 58 | struct perf_evsel { |
53 | 59 | struct list_head node; |
... | ... | @@ -74,6 +80,8 @@ |
74 | 80 | } handler; |
75 | 81 | struct cpu_map *cpus; |
76 | 82 | unsigned int sample_size; |
83 | + int id_pos; | |
84 | + int is_pos; | |
77 | 85 | bool supported; |
78 | 86 | bool needs_swap; |
79 | 87 | /* parse modifier helper */ |
... | ... | @@ -104,6 +112,9 @@ |
104 | 112 | void perf_evsel__config(struct perf_evsel *evsel, |
105 | 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 | 118 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); |
108 | 119 | |
109 | 120 | #define PERF_EVSEL__MAX_ALIASES 8 |
... | ... | @@ -142,7 +153,8 @@ |
142 | 153 | #define perf_evsel__reset_sample_bit(evsel, bit) \ |
143 | 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 | 159 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, |
148 | 160 | const char *filter); |
tools/perf/util/record.c
1 | 1 | #include "evlist.h" |
2 | 2 | #include "evsel.h" |
3 | 3 | #include "cpumap.h" |
4 | +#include "parse-events.h" | |
4 | 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 | +} | |
74 | + | |
5 | 75 | void perf_evlist__config(struct perf_evlist *evlist, |
6 | 76 | struct perf_record_opts *opts) |
7 | 77 | { |
8 | 78 | struct perf_evsel *evsel; |
79 | + bool use_sample_identifier = false; | |
80 | + | |
9 | 81 | /* |
10 | 82 | * Set the evsel leader links before we configure attributes, |
11 | 83 | * since some might depend on this info. |
12 | 84 | |
13 | 85 | |
... | ... | @@ -16,11 +88,22 @@ |
16 | 88 | if (evlist->cpus->map[0] < 0) |
17 | 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 | 92 | perf_evsel__config(evsel, opts); |
21 | 93 | |
22 | - if (evlist->nr_entries > 1) | |
23 | - perf_evsel__set_sample_id(evsel); | |
94 | + if (evlist->nr_entries > 1) { | |
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 | } |
tools/perf/util/session.c
... | ... | @@ -739,7 +739,7 @@ |
739 | 739 | union perf_event *event, |
740 | 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 | 744 | if (event->header.type != PERF_RECORD_SAMPLE && |
745 | 745 | !perf_evlist__sample_id_all(session->evlist)) { |