aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2013-08-27 04:23:09 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-08-29 15:09:31 -0400
commit75562573bab35b129cfd342fc2bcf89da84a6644 (patch)
treeb7dfa219d1a73560ce95639b7291f377645497ba /tools
parentfaf967068e8c4d8df52f01f9361241101b3065a0 (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.c2
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/util/event.h3
-rw-r--r--tools/perf/util/evlist.c111
-rw-r--r--tools/perf/util/evlist.h8
-rw-r--r--tools/perf/util/evsel.c101
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/record.c89
-rw-r--r--tools/perf/util/session.c2
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,
365static int perf_report__setup_sample_type(struct perf_report *rep) 365static 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
58struct sample_event { 59struct 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 */
59void 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
52static void perf_evlist__purge(struct perf_evlist *evlist) 67static 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)
79void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 94void 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
85void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 101void 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
93void __perf_evlist__set_leader(struct list_head *list) 113void __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
372static 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
393static 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
352union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 421union 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
660bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) 729bool 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
672u64 perf_evlist__sample_type(struct perf_evlist *evlist) 748u64 __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
761u64 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
678bool perf_evlist__valid_read_format(struct perf_evlist *evlist) 767bool 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);
730out: 822out:
731 return size; 823 return size;
732} 824}
@@ -885,7 +977,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
885int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, 977int 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);
85int perf_evlist__open(struct perf_evlist *evlist); 88int perf_evlist__open(struct perf_evlist *evlist);
86void perf_evlist__close(struct perf_evlist *evlist); 89void perf_evlist__close(struct perf_evlist *evlist);
87 90
91void perf_evlist__set_id_pos(struct perf_evlist *evlist);
92bool perf_can_sample_identifier(void);
88void perf_evlist__config(struct perf_evlist *evlist, 93void 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);
121void perf_evlist__set_leader(struct perf_evlist *evlist); 126void perf_evlist__set_leader(struct perf_evlist *evlist);
122 127
123u64 perf_evlist__read_format(struct perf_evlist *evlist); 128u64 perf_evlist__read_format(struct perf_evlist *evlist);
124u64 perf_evlist__sample_type(struct perf_evlist *evlist); 129u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist);
130u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist);
125bool perf_evlist__sample_id_all(struct perf_evlist *evlist); 131bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
126u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); 132u16 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
34static int __perf_evsel__sample_size(u64 sample_type) 34int __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 */
58static 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 */
91static 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
110void 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
50void hists__init(struct hists *hists) 116void 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
78void perf_evsel__set_sample_id(struct perf_evsel *evsel) 146void 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
95struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 170struct 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 */
52struct perf_evsel { 58struct 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);
104void perf_evsel__config(struct perf_evsel *evsel, 112void perf_evsel__config(struct perf_evsel *evsel,
105 struct perf_record_opts *opts); 113 struct perf_record_opts *opts);
106 114
115int __perf_evsel__sample_size(u64 sample_type);
116void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
117
107bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 118bool 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
145void perf_evsel__set_sample_id(struct perf_evsel *evsel); 156void perf_evsel__set_sample_id(struct perf_evsel *evsel,
157 bool use_sample_identifier);
146 158
147int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 159int 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
6typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
7
8static 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
39out_delete:
40 perf_evlist__delete(evlist);
41 return err;
42}
43
44static 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
65static void perf_probe_sample_identifier(struct perf_evsel *evsel)
66{
67 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
68}
69
70bool perf_can_sample_identifier(void)
71{
72 return perf_probe_api(perf_probe_sample_identifier);
73}
4 74
5void perf_evlist__config(struct perf_evlist *evlist, 75void 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)) {