aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2014-10-27 09:49:22 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-10-29 09:24:47 -0400
commit3c659eedada2fbf909c5818848753a6647a56426 (patch)
tree9aeba4f9f1bdbba845f24f560a59c18db1ade3eb /tools
parent5e17b28f1e246b98e08cb463f7d72cff6415fc53 (diff)
perf tools: Add id index
Add an index of the event identifiers, in preparation for Intel PT. The event id (also called the sample id) is a unique number allocated by the kernel to the event created by perf_event_open(). Events can include the event id by having a sample type including PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER. Currently the main use of the event id is to match an event back to the evsel to which it belongs i.e. perf_evlist__id2evsel() The purpose of this patch is to make it possible to match an event back to the mmap from which it was read. The reason that is useful is because the mmap represents a time-ordered context (either for a cpu or for a thread). Intel PT decodes trace information on that basis. In full-trace mode, that information can be recorded when the Intel PT trace is read, but in sample-mode the Intel PT trace data is embedded in a sample and it is in that case that the "id index" is needed. So the mmaps are numbered (idx) and the cpu and tid recorded against the id by perf_evlist__set_sid_idx() which is called by perf_evlist__mmap_per_evsel(). That information is recorded on the perf.data file in the new "id index". idx, cpu and tid are added to struct perf_sample_id (which is the node of evlist's hash table to match ids to evsels). The information can be retrieved using perf_evlist__id2sid(). Note however this all depends on having a sample type including PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER, otherwise ids are not recorded. The "id index" is a synthesized event record which will be created when Intel PT sampling is used by calling perf_event__synthesize_id_index(). Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> 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/1414417770-18602-2-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-inject.c1
-rw-r--r--tools/perf/util/event.c1
-rw-r--r--tools/perf/util/event.h15
-rw-r--r--tools/perf/util/evlist.c26
-rw-r--r--tools/perf/util/evsel.h3
-rw-r--r--tools/perf/util/session.c122
-rw-r--r--tools/perf/util/session.h10
-rw-r--r--tools/perf/util/tool.h3
8 files changed, 177 insertions, 4 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 06f1758951f1..84df2deed988 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -409,6 +409,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
409 .tracing_data = perf_event__repipe_op2_synth, 409 .tracing_data = perf_event__repipe_op2_synth,
410 .finished_round = perf_event__repipe_op2_synth, 410 .finished_round = perf_event__repipe_op2_synth,
411 .build_id = perf_event__repipe_op2_synth, 411 .build_id = perf_event__repipe_op2_synth,
412 .id_index = perf_event__repipe_op2_synth,
412 }, 413 },
413 .input_name = "-", 414 .input_name = "-",
414 .samples = LIST_HEAD_INIT(inject.samples), 415 .samples = LIST_HEAD_INIT(inject.samples),
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index e00a29fb099f..6c6d044e959a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -28,6 +28,7 @@ static const char *perf_event__names[] = {
28 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 28 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
29 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 29 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
30 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 30 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
31 [PERF_RECORD_ID_INDEX] = "ID_INDEX",
31}; 32};
32 33
33const char *perf_event__name(unsigned int id) 34const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 5f0e0b89e130..8c7fe9d64e79 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -187,6 +187,7 @@ enum perf_user_event_type { /* above any possible kernel type */
187 PERF_RECORD_HEADER_TRACING_DATA = 66, 187 PERF_RECORD_HEADER_TRACING_DATA = 66,
188 PERF_RECORD_HEADER_BUILD_ID = 67, 188 PERF_RECORD_HEADER_BUILD_ID = 67,
189 PERF_RECORD_FINISHED_ROUND = 68, 189 PERF_RECORD_FINISHED_ROUND = 68,
190 PERF_RECORD_ID_INDEX = 69,
190 PERF_RECORD_HEADER_MAX 191 PERF_RECORD_HEADER_MAX
191}; 192};
192 193
@@ -239,6 +240,19 @@ struct tracing_data_event {
239 u32 size; 240 u32 size;
240}; 241};
241 242
243struct id_index_entry {
244 u64 id;
245 u64 idx;
246 u64 cpu;
247 u64 tid;
248};
249
250struct id_index_event {
251 struct perf_event_header header;
252 u64 nr;
253 struct id_index_entry entries[0];
254};
255
242union perf_event { 256union perf_event {
243 struct perf_event_header header; 257 struct perf_event_header header;
244 struct mmap_event mmap; 258 struct mmap_event mmap;
@@ -253,6 +267,7 @@ union perf_event {
253 struct event_type_event event_type; 267 struct event_type_event event_type;
254 struct tracing_data_event tracing_data; 268 struct tracing_data_event tracing_data;
255 struct build_id_event build_id; 269 struct build_id_event build_id;
270 struct id_index_event id_index;
256}; 271};
257 272
258void perf_event__print_totals(void); 273void perf_event__print_totals(void);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3c9e77d6b4c2..0babd390963c 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -527,6 +527,22 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
527 return 0; 527 return 0;
528} 528}
529 529
530static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
531 struct perf_evsel *evsel, int idx, int cpu,
532 int thread)
533{
534 struct perf_sample_id *sid = SID(evsel, cpu, thread);
535 sid->idx = idx;
536 if (evlist->cpus && cpu >= 0)
537 sid->cpu = evlist->cpus->map[cpu];
538 else
539 sid->cpu = -1;
540 if (!evsel->system_wide && evlist->threads && thread >= 0)
541 sid->tid = evlist->threads->map[thread];
542 else
543 sid->tid = -1;
544}
545
530struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id) 546struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
531{ 547{
532 struct hlist_head *head; 548 struct hlist_head *head;
@@ -805,9 +821,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
805 return -1; 821 return -1;
806 } 822 }
807 823
808 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 824 if (evsel->attr.read_format & PERF_FORMAT_ID) {
809 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) 825 if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
810 return -1; 826 fd) < 0)
827 return -1;
828 perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
829 thread);
830 }
811 } 831 }
812 832
813 return 0; 833 return 0;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index d3854c4f52e1..979790951bfb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -36,6 +36,9 @@ struct perf_sample_id {
36 struct hlist_node node; 36 struct hlist_node node;
37 u64 id; 37 u64 id;
38 struct perf_evsel *evsel; 38 struct perf_evsel *evsel;
39 int idx;
40 int cpu;
41 pid_t tid;
39 42
40 /* Holds total ID period value for PERF_SAMPLE_READ processing. */ 43 /* Holds total ID period value for PERF_SAMPLE_READ processing. */
41 u64 period; 44 u64 period;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 776010844cdc..27a0049118b5 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -228,6 +228,15 @@ static int process_finished_round(struct perf_tool *tool,
228 union perf_event *event, 228 union perf_event *event,
229 struct perf_session *session); 229 struct perf_session *session);
230 230
231static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
232 union perf_event *event __maybe_unused,
233 struct perf_session *perf_session
234 __maybe_unused)
235{
236 dump_printf(": unhandled!\n");
237 return 0;
238}
239
231void perf_tool__fill_defaults(struct perf_tool *tool) 240void perf_tool__fill_defaults(struct perf_tool *tool)
232{ 241{
233 if (tool->sample == NULL) 242 if (tool->sample == NULL)
@@ -262,6 +271,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
262 else 271 else
263 tool->finished_round = process_finished_round_stub; 272 tool->finished_round = process_finished_round_stub;
264 } 273 }
274 if (tool->id_index == NULL)
275 tool->id_index = process_id_index_stub;
265} 276}
266 277
267static void swap_sample_id_all(union perf_event *event, void *data) 278static void swap_sample_id_all(union perf_event *event, void *data)
@@ -460,6 +471,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
460 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, 471 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
461 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, 472 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
462 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 473 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
474 [PERF_RECORD_ID_INDEX] = perf_event__all64_swap,
463 [PERF_RECORD_HEADER_MAX] = NULL, 475 [PERF_RECORD_HEADER_MAX] = NULL,
464}; 476};
465 477
@@ -888,6 +900,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
888 return tool->build_id(tool, event, session); 900 return tool->build_id(tool, event, session);
889 case PERF_RECORD_FINISHED_ROUND: 901 case PERF_RECORD_FINISHED_ROUND:
890 return tool->finished_round(tool, event, session); 902 return tool->finished_round(tool, event, session);
903 case PERF_RECORD_ID_INDEX:
904 return tool->id_index(tool, event, session);
891 default: 905 default:
892 return -EINVAL; 906 return -EINVAL;
893 } 907 }
@@ -1594,3 +1608,111 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1594out: 1608out:
1595 return err; 1609 return err;
1596} 1610}
1611
1612int perf_event__process_id_index(struct perf_tool *tool __maybe_unused,
1613 union perf_event *event,
1614 struct perf_session *session)
1615{
1616 struct perf_evlist *evlist = session->evlist;
1617 struct id_index_event *ie = &event->id_index;
1618 size_t i, nr, max_nr;
1619
1620 max_nr = (ie->header.size - sizeof(struct id_index_event)) /
1621 sizeof(struct id_index_entry);
1622 nr = ie->nr;
1623 if (nr > max_nr)
1624 return -EINVAL;
1625
1626 if (dump_trace)
1627 fprintf(stdout, " nr: %zu\n", nr);
1628
1629 for (i = 0; i < nr; i++) {
1630 struct id_index_entry *e = &ie->entries[i];
1631 struct perf_sample_id *sid;
1632
1633 if (dump_trace) {
1634 fprintf(stdout, " ... id: %"PRIu64, e->id);
1635 fprintf(stdout, " idx: %"PRIu64, e->idx);
1636 fprintf(stdout, " cpu: %"PRId64, e->cpu);
1637 fprintf(stdout, " tid: %"PRId64"\n", e->tid);
1638 }
1639
1640 sid = perf_evlist__id2sid(evlist, e->id);
1641 if (!sid)
1642 return -ENOENT;
1643 sid->idx = e->idx;
1644 sid->cpu = e->cpu;
1645 sid->tid = e->tid;
1646 }
1647 return 0;
1648}
1649
1650int perf_event__synthesize_id_index(struct perf_tool *tool,
1651 perf_event__handler_t process,
1652 struct perf_evlist *evlist,
1653 struct machine *machine)
1654{
1655 union perf_event *ev;
1656 struct perf_evsel *evsel;
1657 size_t nr = 0, i = 0, sz, max_nr, n;
1658 int err;
1659
1660 pr_debug2("Synthesizing id index\n");
1661
1662 max_nr = (UINT16_MAX - sizeof(struct id_index_event)) /
1663 sizeof(struct id_index_entry);
1664
1665 list_for_each_entry(evsel, &evlist->entries, node)
1666 nr += evsel->ids;
1667
1668 n = nr > max_nr ? max_nr : nr;
1669 sz = sizeof(struct id_index_event) + n * sizeof(struct id_index_entry);
1670 ev = zalloc(sz);
1671 if (!ev)
1672 return -ENOMEM;
1673
1674 ev->id_index.header.type = PERF_RECORD_ID_INDEX;
1675 ev->id_index.header.size = sz;
1676 ev->id_index.nr = n;
1677
1678 list_for_each_entry(evsel, &evlist->entries, node) {
1679 u32 j;
1680
1681 for (j = 0; j < evsel->ids; j++) {
1682 struct id_index_entry *e;
1683 struct perf_sample_id *sid;
1684
1685 if (i >= n) {
1686 err = process(tool, ev, NULL, machine);
1687 if (err)
1688 goto out_err;
1689 nr -= n;
1690 i = 0;
1691 }
1692
1693 e = &ev->id_index.entries[i++];
1694
1695 e->id = evsel->id[j];
1696
1697 sid = perf_evlist__id2sid(evlist, e->id);
1698 if (!sid) {
1699 free(ev);
1700 return -ENOENT;
1701 }
1702
1703 e->idx = sid->idx;
1704 e->cpu = sid->cpu;
1705 e->tid = sid->tid;
1706 }
1707 }
1708
1709 sz = sizeof(struct id_index_event) + nr * sizeof(struct id_index_entry);
1710 ev->id_index.header.size = sz;
1711 ev->id_index.nr = nr;
1712
1713 err = process(tool, ev, NULL, machine);
1714out_err:
1715 free(ev);
1716
1717 return err;
1718}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index a4be851f1a90..d8521ac73a10 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -126,4 +126,14 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
126extern volatile int session_done; 126extern volatile int session_done;
127 127
128#define session_done() ACCESS_ONCE(session_done) 128#define session_done() ACCESS_ONCE(session_done)
129
130int perf_event__process_id_index(struct perf_tool *tool,
131 union perf_event *event,
132 struct perf_session *session);
133
134int perf_event__synthesize_id_index(struct perf_tool *tool,
135 perf_event__handler_t process,
136 struct perf_evlist *evlist,
137 struct machine *machine);
138
129#endif /* __PERF_SESSION_H */ 139#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index f11636966a0f..bb2708bbfaca 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -39,7 +39,8 @@ struct perf_tool {
39 event_attr_op attr; 39 event_attr_op attr;
40 event_op2 tracing_data; 40 event_op2 tracing_data;
41 event_op2 finished_round, 41 event_op2 finished_round,
42 build_id; 42 build_id,
43 id_index;
43 bool ordered_events; 44 bool ordered_events;
44 bool ordering_requires_timestamps; 45 bool ordering_requires_timestamps;
45}; 46};