diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 241 |
1 files changed, 175 insertions, 66 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index cf1fe01b7e89..1fc0c628683e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <traceevent/event-parse.h> | ||
2 | 3 | ||
3 | #include <byteswap.h> | 4 | #include <byteswap.h> |
4 | #include <unistd.h> | 5 | #include <unistd.h> |
@@ -12,7 +13,6 @@ | |||
12 | #include "sort.h" | 13 | #include "sort.h" |
13 | #include "util.h" | 14 | #include "util.h" |
14 | #include "cpumap.h" | 15 | #include "cpumap.h" |
15 | #include "event-parse.h" | ||
16 | #include "perf_regs.h" | 16 | #include "perf_regs.h" |
17 | #include "vdso.h" | 17 | #include "vdso.h" |
18 | 18 | ||
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
24 | self->fd_pipe = true; | 24 | self->fd_pipe = true; |
25 | self->fd = STDIN_FILENO; | 25 | self->fd = STDIN_FILENO; |
26 | 26 | ||
27 | if (perf_session__read_header(self, self->fd) < 0) | 27 | if (perf_session__read_header(self) < 0) |
28 | pr_err("incompatible file format (rerun with -v to learn more)"); | 28 | pr_err("incompatible file format (rerun with -v to learn more)"); |
29 | 29 | ||
30 | return 0; | 30 | return 0; |
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
56 | goto out_close; | 56 | goto out_close; |
57 | } | 57 | } |
58 | 58 | ||
59 | if (perf_session__read_header(self, self->fd) < 0) { | 59 | if (perf_session__read_header(self) < 0) { |
60 | pr_err("incompatible file format (rerun with -v to learn more)"); | 60 | pr_err("incompatible file format (rerun with -v to learn more)"); |
61 | goto out_close; | 61 | goto out_close; |
62 | } | 62 | } |
@@ -71,6 +71,11 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
71 | goto out_close; | 71 | goto out_close; |
72 | } | 72 | } |
73 | 73 | ||
74 | if (!perf_evlist__valid_read_format(self->evlist)) { | ||
75 | pr_err("non matching read_format"); | ||
76 | goto out_close; | ||
77 | } | ||
78 | |||
74 | self->size = input_stat.st_size; | 79 | self->size = input_stat.st_size; |
75 | return 0; | 80 | return 0; |
76 | 81 | ||
@@ -193,7 +198,9 @@ void perf_session__delete(struct perf_session *self) | |||
193 | vdso__exit(); | 198 | vdso__exit(); |
194 | } | 199 | } |
195 | 200 | ||
196 | static int process_event_synth_tracing_data_stub(union perf_event *event | 201 | static int process_event_synth_tracing_data_stub(struct perf_tool *tool |
202 | __maybe_unused, | ||
203 | union perf_event *event | ||
197 | __maybe_unused, | 204 | __maybe_unused, |
198 | struct perf_session *session | 205 | struct perf_session *session |
199 | __maybe_unused) | 206 | __maybe_unused) |
@@ -202,7 +209,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event | |||
202 | return 0; | 209 | return 0; |
203 | } | 210 | } |
204 | 211 | ||
205 | static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, | 212 | static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, |
213 | union perf_event *event __maybe_unused, | ||
206 | struct perf_evlist **pevlist | 214 | struct perf_evlist **pevlist |
207 | __maybe_unused) | 215 | __maybe_unused) |
208 | { | 216 | { |
@@ -238,18 +246,11 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, | |||
238 | return 0; | 246 | return 0; |
239 | } | 247 | } |
240 | 248 | ||
241 | static int process_event_type_stub(struct perf_tool *tool __maybe_unused, | ||
242 | union perf_event *event __maybe_unused) | ||
243 | { | ||
244 | dump_printf(": unhandled!\n"); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int process_finished_round(struct perf_tool *tool, | 249 | static int process_finished_round(struct perf_tool *tool, |
249 | union perf_event *event, | 250 | union perf_event *event, |
250 | struct perf_session *session); | 251 | struct perf_session *session); |
251 | 252 | ||
252 | static void perf_tool__fill_defaults(struct perf_tool *tool) | 253 | void perf_tool__fill_defaults(struct perf_tool *tool) |
253 | { | 254 | { |
254 | if (tool->sample == NULL) | 255 | if (tool->sample == NULL) |
255 | tool->sample = process_event_sample_stub; | 256 | tool->sample = process_event_sample_stub; |
@@ -271,8 +272,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool) | |||
271 | tool->unthrottle = process_event_stub; | 272 | tool->unthrottle = process_event_stub; |
272 | if (tool->attr == NULL) | 273 | if (tool->attr == NULL) |
273 | tool->attr = process_event_synth_attr_stub; | 274 | tool->attr = process_event_synth_attr_stub; |
274 | if (tool->event_type == NULL) | ||
275 | tool->event_type = process_event_type_stub; | ||
276 | if (tool->tracing_data == NULL) | 275 | if (tool->tracing_data == NULL) |
277 | tool->tracing_data = process_event_synth_tracing_data_stub; | 276 | tool->tracing_data = process_event_synth_tracing_data_stub; |
278 | if (tool->build_id == NULL) | 277 | if (tool->build_id == NULL) |
@@ -496,7 +495,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
496 | u64 file_offset); | 495 | u64 file_offset); |
497 | 496 | ||
498 | static int flush_sample_queue(struct perf_session *s, | 497 | static int flush_sample_queue(struct perf_session *s, |
499 | struct perf_tool *tool) | 498 | struct perf_tool *tool) |
500 | { | 499 | { |
501 | struct ordered_samples *os = &s->ordered_samples; | 500 | struct ordered_samples *os = &s->ordered_samples; |
502 | struct list_head *head = &os->samples; | 501 | struct list_head *head = &os->samples; |
@@ -644,7 +643,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) | |||
644 | 643 | ||
645 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | 644 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
646 | 645 | ||
647 | static int perf_session_queue_event(struct perf_session *s, union perf_event *event, | 646 | int perf_session_queue_event(struct perf_session *s, union perf_event *event, |
648 | struct perf_sample *sample, u64 file_offset) | 647 | struct perf_sample *sample, u64 file_offset) |
649 | { | 648 | { |
650 | struct ordered_samples *os = &s->ordered_samples; | 649 | struct ordered_samples *os = &s->ordered_samples; |
@@ -740,7 +739,7 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
740 | union perf_event *event, | 739 | union perf_event *event, |
741 | struct perf_sample *sample) | 740 | struct perf_sample *sample) |
742 | { | 741 | { |
743 | u64 sample_type = perf_evlist__sample_type(session->evlist); | 742 | u64 sample_type = __perf_evlist__combined_sample_type(session->evlist); |
744 | 743 | ||
745 | if (event->header.type != PERF_RECORD_SAMPLE && | 744 | if (event->header.type != PERF_RECORD_SAMPLE && |
746 | !perf_evlist__sample_id_all(session->evlist)) { | 745 | !perf_evlist__sample_id_all(session->evlist)) { |
@@ -755,6 +754,36 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
755 | printf("%" PRIu64 " ", sample->time); | 754 | printf("%" PRIu64 " ", sample->time); |
756 | } | 755 | } |
757 | 756 | ||
757 | static void sample_read__printf(struct perf_sample *sample, u64 read_format) | ||
758 | { | ||
759 | printf("... sample_read:\n"); | ||
760 | |||
761 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) | ||
762 | printf("...... time enabled %016" PRIx64 "\n", | ||
763 | sample->read.time_enabled); | ||
764 | |||
765 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) | ||
766 | printf("...... time running %016" PRIx64 "\n", | ||
767 | sample->read.time_running); | ||
768 | |||
769 | if (read_format & PERF_FORMAT_GROUP) { | ||
770 | u64 i; | ||
771 | |||
772 | printf(".... group nr %" PRIu64 "\n", sample->read.group.nr); | ||
773 | |||
774 | for (i = 0; i < sample->read.group.nr; i++) { | ||
775 | struct sample_read_value *value; | ||
776 | |||
777 | value = &sample->read.group.values[i]; | ||
778 | printf("..... id %016" PRIx64 | ||
779 | ", value %016" PRIx64 "\n", | ||
780 | value->id, value->value); | ||
781 | } | ||
782 | } else | ||
783 | printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n", | ||
784 | sample->read.one.id, sample->read.one.value); | ||
785 | } | ||
786 | |||
758 | static void dump_event(struct perf_session *session, union perf_event *event, | 787 | static void dump_event(struct perf_session *session, union perf_event *event, |
759 | u64 file_offset, struct perf_sample *sample) | 788 | u64 file_offset, struct perf_sample *sample) |
760 | { | 789 | { |
@@ -804,11 +833,15 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
804 | 833 | ||
805 | if (sample_type & PERF_SAMPLE_DATA_SRC) | 834 | if (sample_type & PERF_SAMPLE_DATA_SRC) |
806 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); | 835 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); |
836 | |||
837 | if (sample_type & PERF_SAMPLE_READ) | ||
838 | sample_read__printf(sample, evsel->attr.read_format); | ||
807 | } | 839 | } |
808 | 840 | ||
809 | static struct machine * | 841 | static struct machine * |
810 | perf_session__find_machine_for_cpumode(struct perf_session *session, | 842 | perf_session__find_machine_for_cpumode(struct perf_session *session, |
811 | union perf_event *event) | 843 | union perf_event *event, |
844 | struct perf_sample *sample) | ||
812 | { | 845 | { |
813 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 846 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
814 | 847 | ||
@@ -820,7 +853,7 @@ static struct machine * | |||
820 | if (event->header.type == PERF_RECORD_MMAP) | 853 | if (event->header.type == PERF_RECORD_MMAP) |
821 | pid = event->mmap.pid; | 854 | pid = event->mmap.pid; |
822 | else | 855 | else |
823 | pid = event->ip.pid; | 856 | pid = sample->pid; |
824 | 857 | ||
825 | return perf_session__findnew_machine(session, pid); | 858 | return perf_session__findnew_machine(session, pid); |
826 | } | 859 | } |
@@ -828,6 +861,75 @@ static struct machine * | |||
828 | return &session->machines.host; | 861 | return &session->machines.host; |
829 | } | 862 | } |
830 | 863 | ||
864 | static int deliver_sample_value(struct perf_session *session, | ||
865 | struct perf_tool *tool, | ||
866 | union perf_event *event, | ||
867 | struct perf_sample *sample, | ||
868 | struct sample_read_value *v, | ||
869 | struct machine *machine) | ||
870 | { | ||
871 | struct perf_sample_id *sid; | ||
872 | |||
873 | sid = perf_evlist__id2sid(session->evlist, v->id); | ||
874 | if (sid) { | ||
875 | sample->id = v->id; | ||
876 | sample->period = v->value - sid->period; | ||
877 | sid->period = v->value; | ||
878 | } | ||
879 | |||
880 | if (!sid || sid->evsel == NULL) { | ||
881 | ++session->stats.nr_unknown_id; | ||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | return tool->sample(tool, event, sample, sid->evsel, machine); | ||
886 | } | ||
887 | |||
888 | static int deliver_sample_group(struct perf_session *session, | ||
889 | struct perf_tool *tool, | ||
890 | union perf_event *event, | ||
891 | struct perf_sample *sample, | ||
892 | struct machine *machine) | ||
893 | { | ||
894 | int ret = -EINVAL; | ||
895 | u64 i; | ||
896 | |||
897 | for (i = 0; i < sample->read.group.nr; i++) { | ||
898 | ret = deliver_sample_value(session, tool, event, sample, | ||
899 | &sample->read.group.values[i], | ||
900 | machine); | ||
901 | if (ret) | ||
902 | break; | ||
903 | } | ||
904 | |||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | static int | ||
909 | perf_session__deliver_sample(struct perf_session *session, | ||
910 | struct perf_tool *tool, | ||
911 | union perf_event *event, | ||
912 | struct perf_sample *sample, | ||
913 | struct perf_evsel *evsel, | ||
914 | struct machine *machine) | ||
915 | { | ||
916 | /* We know evsel != NULL. */ | ||
917 | u64 sample_type = evsel->attr.sample_type; | ||
918 | u64 read_format = evsel->attr.read_format; | ||
919 | |||
920 | /* Standard sample delievery. */ | ||
921 | if (!(sample_type & PERF_SAMPLE_READ)) | ||
922 | return tool->sample(tool, event, sample, evsel, machine); | ||
923 | |||
924 | /* For PERF_SAMPLE_READ we have either single or group mode. */ | ||
925 | if (read_format & PERF_FORMAT_GROUP) | ||
926 | return deliver_sample_group(session, tool, event, sample, | ||
927 | machine); | ||
928 | else | ||
929 | return deliver_sample_value(session, tool, event, sample, | ||
930 | &sample->read.one, machine); | ||
931 | } | ||
932 | |||
831 | static int perf_session_deliver_event(struct perf_session *session, | 933 | static int perf_session_deliver_event(struct perf_session *session, |
832 | union perf_event *event, | 934 | union perf_event *event, |
833 | struct perf_sample *sample, | 935 | struct perf_sample *sample, |
@@ -857,7 +959,8 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
857 | hists__inc_nr_events(&evsel->hists, event->header.type); | 959 | hists__inc_nr_events(&evsel->hists, event->header.type); |
858 | } | 960 | } |
859 | 961 | ||
860 | machine = perf_session__find_machine_for_cpumode(session, event); | 962 | machine = perf_session__find_machine_for_cpumode(session, event, |
963 | sample); | ||
861 | 964 | ||
862 | switch (event->header.type) { | 965 | switch (event->header.type) { |
863 | case PERF_RECORD_SAMPLE: | 966 | case PERF_RECORD_SAMPLE: |
@@ -870,7 +973,8 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
870 | ++session->stats.nr_unprocessable_samples; | 973 | ++session->stats.nr_unprocessable_samples; |
871 | return 0; | 974 | return 0; |
872 | } | 975 | } |
873 | return tool->sample(tool, event, sample, evsel, machine); | 976 | return perf_session__deliver_sample(session, tool, event, |
977 | sample, evsel, machine); | ||
874 | case PERF_RECORD_MMAP: | 978 | case PERF_RECORD_MMAP: |
875 | return tool->mmap(tool, event, sample, machine); | 979 | return tool->mmap(tool, event, sample, machine); |
876 | case PERF_RECORD_COMM: | 980 | case PERF_RECORD_COMM: |
@@ -895,22 +999,6 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
895 | } | 999 | } |
896 | } | 1000 | } |
897 | 1001 | ||
898 | static int perf_session__preprocess_sample(struct perf_session *session, | ||
899 | union perf_event *event, struct perf_sample *sample) | ||
900 | { | ||
901 | if (event->header.type != PERF_RECORD_SAMPLE || | ||
902 | !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN)) | ||
903 | return 0; | ||
904 | |||
905 | if (!ip_callchain__valid(sample->callchain, event)) { | ||
906 | pr_debug("call-chain problem with event, skipping it.\n"); | ||
907 | ++session->stats.nr_invalid_chains; | ||
908 | session->stats.total_invalid_chains += sample->period; | ||
909 | return -EINVAL; | ||
910 | } | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, | 1002 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, |
915 | struct perf_tool *tool, u64 file_offset) | 1003 | struct perf_tool *tool, u64 file_offset) |
916 | { | 1004 | { |
@@ -921,16 +1009,14 @@ static int perf_session__process_user_event(struct perf_session *session, union | |||
921 | /* These events are processed right away */ | 1009 | /* These events are processed right away */ |
922 | switch (event->header.type) { | 1010 | switch (event->header.type) { |
923 | case PERF_RECORD_HEADER_ATTR: | 1011 | case PERF_RECORD_HEADER_ATTR: |
924 | err = tool->attr(event, &session->evlist); | 1012 | err = tool->attr(tool, event, &session->evlist); |
925 | if (err == 0) | 1013 | if (err == 0) |
926 | perf_session__set_id_hdr_size(session); | 1014 | perf_session__set_id_hdr_size(session); |
927 | return err; | 1015 | return err; |
928 | case PERF_RECORD_HEADER_EVENT_TYPE: | ||
929 | return tool->event_type(tool, event); | ||
930 | case PERF_RECORD_HEADER_TRACING_DATA: | 1016 | case PERF_RECORD_HEADER_TRACING_DATA: |
931 | /* setup for reading amidst mmap */ | 1017 | /* setup for reading amidst mmap */ |
932 | lseek(session->fd, file_offset, SEEK_SET); | 1018 | lseek(session->fd, file_offset, SEEK_SET); |
933 | return tool->tracing_data(event, session); | 1019 | return tool->tracing_data(tool, event, session); |
934 | case PERF_RECORD_HEADER_BUILD_ID: | 1020 | case PERF_RECORD_HEADER_BUILD_ID: |
935 | return tool->build_id(tool, event, session); | 1021 | return tool->build_id(tool, event, session); |
936 | case PERF_RECORD_FINISHED_ROUND: | 1022 | case PERF_RECORD_FINISHED_ROUND: |
@@ -975,10 +1061,6 @@ static int perf_session__process_event(struct perf_session *session, | |||
975 | if (ret) | 1061 | if (ret) |
976 | return ret; | 1062 | return ret; |
977 | 1063 | ||
978 | /* Preprocess sample records - precheck callchains */ | ||
979 | if (perf_session__preprocess_sample(session, event, &sample)) | ||
980 | return 0; | ||
981 | |||
982 | if (tool->ordered_samples) { | 1064 | if (tool->ordered_samples) { |
983 | ret = perf_session_queue_event(session, event, &sample, | 1065 | ret = perf_session_queue_event(session, event, &sample, |
984 | file_offset); | 1066 | file_offset); |
@@ -999,7 +1081,7 @@ void perf_event_header__bswap(struct perf_event_header *self) | |||
999 | 1081 | ||
1000 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) | 1082 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) |
1001 | { | 1083 | { |
1002 | return machine__findnew_thread(&session->machines.host, pid); | 1084 | return machine__findnew_thread(&session->machines.host, 0, pid); |
1003 | } | 1085 | } |
1004 | 1086 | ||
1005 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) | 1087 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) |
@@ -1091,8 +1173,10 @@ more: | |||
1091 | perf_event_header__bswap(&event->header); | 1173 | perf_event_header__bswap(&event->header); |
1092 | 1174 | ||
1093 | size = event->header.size; | 1175 | size = event->header.size; |
1094 | if (size == 0) | 1176 | if (size < sizeof(struct perf_event_header)) { |
1095 | size = 8; | 1177 | pr_err("bad event header size\n"); |
1178 | goto out_err; | ||
1179 | } | ||
1096 | 1180 | ||
1097 | if (size > cur_size) { | 1181 | if (size > cur_size) { |
1098 | void *new = realloc(buf, size); | 1182 | void *new = realloc(buf, size); |
@@ -1161,8 +1245,12 @@ fetch_mmaped_event(struct perf_session *session, | |||
1161 | if (session->header.needs_swap) | 1245 | if (session->header.needs_swap) |
1162 | perf_event_header__bswap(&event->header); | 1246 | perf_event_header__bswap(&event->header); |
1163 | 1247 | ||
1164 | if (head + event->header.size > mmap_size) | 1248 | if (head + event->header.size > mmap_size) { |
1249 | /* We're not fetching the event so swap back again */ | ||
1250 | if (session->header.needs_swap) | ||
1251 | perf_event_header__bswap(&event->header); | ||
1165 | return NULL; | 1252 | return NULL; |
1253 | } | ||
1166 | 1254 | ||
1167 | return event; | 1255 | return event; |
1168 | } | 1256 | } |
@@ -1242,7 +1330,7 @@ more: | |||
1242 | 1330 | ||
1243 | size = event->header.size; | 1331 | size = event->header.size; |
1244 | 1332 | ||
1245 | if (size == 0 || | 1333 | if (size < sizeof(struct perf_event_header) || |
1246 | perf_session__process_event(session, event, tool, file_pos) < 0) { | 1334 | perf_session__process_event(session, event, tool, file_pos) < 0) { |
1247 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", | 1335 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", |
1248 | file_offset + head, event->header.size, | 1336 | file_offset + head, event->header.size, |
@@ -1295,12 +1383,15 @@ int perf_session__process_events(struct perf_session *self, | |||
1295 | 1383 | ||
1296 | bool perf_session__has_traces(struct perf_session *session, const char *msg) | 1384 | bool perf_session__has_traces(struct perf_session *session, const char *msg) |
1297 | { | 1385 | { |
1298 | if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { | 1386 | struct perf_evsel *evsel; |
1299 | pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); | 1387 | |
1300 | return false; | 1388 | list_for_each_entry(evsel, &session->evlist->entries, node) { |
1389 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) | ||
1390 | return true; | ||
1301 | } | 1391 | } |
1302 | 1392 | ||
1303 | return true; | 1393 | pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); |
1394 | return false; | ||
1304 | } | 1395 | } |
1305 | 1396 | ||
1306 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, | 1397 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, |
@@ -1383,13 +1474,18 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1383 | 1474 | ||
1384 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 1475 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, |
1385 | struct perf_sample *sample, struct machine *machine, | 1476 | struct perf_sample *sample, struct machine *machine, |
1386 | int print_sym, int print_dso, int print_symoffset) | 1477 | unsigned int print_opts, unsigned int stack_depth) |
1387 | { | 1478 | { |
1388 | struct addr_location al; | 1479 | struct addr_location al; |
1389 | struct callchain_cursor_node *node; | 1480 | struct callchain_cursor_node *node; |
1390 | 1481 | int print_ip = print_opts & PRINT_IP_OPT_IP; | |
1391 | if (perf_event__preprocess_sample(event, machine, &al, sample, | 1482 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
1392 | NULL) < 0) { | 1483 | int print_dso = print_opts & PRINT_IP_OPT_DSO; |
1484 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
1485 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | ||
1486 | char s = print_oneline ? ' ' : '\t'; | ||
1487 | |||
1488 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | ||
1393 | error("problem processing %d event, skipping it.\n", | 1489 | error("problem processing %d event, skipping it.\n", |
1394 | event->header.type); | 1490 | event->header.type); |
1395 | return; | 1491 | return; |
@@ -1397,37 +1493,50 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1397 | 1493 | ||
1398 | if (symbol_conf.use_callchain && sample->callchain) { | 1494 | if (symbol_conf.use_callchain && sample->callchain) { |
1399 | 1495 | ||
1400 | |||
1401 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1496 | if (machine__resolve_callchain(machine, evsel, al.thread, |
1402 | sample, NULL) != 0) { | 1497 | sample, NULL, NULL) != 0) { |
1403 | if (verbose) | 1498 | if (verbose) |
1404 | error("Failed to resolve callchain. Skipping\n"); | 1499 | error("Failed to resolve callchain. Skipping\n"); |
1405 | return; | 1500 | return; |
1406 | } | 1501 | } |
1407 | callchain_cursor_commit(&callchain_cursor); | 1502 | callchain_cursor_commit(&callchain_cursor); |
1408 | 1503 | ||
1409 | while (1) { | 1504 | while (stack_depth) { |
1410 | node = callchain_cursor_current(&callchain_cursor); | 1505 | node = callchain_cursor_current(&callchain_cursor); |
1411 | if (!node) | 1506 | if (!node) |
1412 | break; | 1507 | break; |
1413 | 1508 | ||
1414 | printf("\t%16" PRIx64, node->ip); | 1509 | if (print_ip) |
1510 | printf("%c%16" PRIx64, s, node->ip); | ||
1511 | |||
1415 | if (print_sym) { | 1512 | if (print_sym) { |
1416 | printf(" "); | 1513 | printf(" "); |
1417 | symbol__fprintf_symname(node->sym, stdout); | 1514 | if (print_symoffset) { |
1515 | al.addr = node->ip; | ||
1516 | al.map = node->map; | ||
1517 | symbol__fprintf_symname_offs(node->sym, &al, stdout); | ||
1518 | } else | ||
1519 | symbol__fprintf_symname(node->sym, stdout); | ||
1418 | } | 1520 | } |
1521 | |||
1419 | if (print_dso) { | 1522 | if (print_dso) { |
1420 | printf(" ("); | 1523 | printf(" ("); |
1421 | map__fprintf_dsoname(node->map, stdout); | 1524 | map__fprintf_dsoname(node->map, stdout); |
1422 | printf(")"); | 1525 | printf(")"); |
1423 | } | 1526 | } |
1424 | printf("\n"); | 1527 | |
1528 | if (!print_oneline) | ||
1529 | printf("\n"); | ||
1425 | 1530 | ||
1426 | callchain_cursor_advance(&callchain_cursor); | 1531 | callchain_cursor_advance(&callchain_cursor); |
1532 | |||
1533 | stack_depth--; | ||
1427 | } | 1534 | } |
1428 | 1535 | ||
1429 | } else { | 1536 | } else { |
1430 | printf("%16" PRIx64, sample->ip); | 1537 | if (print_ip) |
1538 | printf("%16" PRIx64, sample->ip); | ||
1539 | |||
1431 | if (print_sym) { | 1540 | if (print_sym) { |
1432 | printf(" "); | 1541 | printf(" "); |
1433 | if (print_symoffset) | 1542 | if (print_symoffset) |