aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r--tools/perf/util/session.c241
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
196static int process_event_synth_tracing_data_stub(union perf_event *event 201static 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
205static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, 212static 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
241static 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
248static int process_finished_round(struct perf_tool *tool, 249static 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
252static void perf_tool__fill_defaults(struct perf_tool *tool) 253void 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
498static int flush_sample_queue(struct perf_session *s, 497static 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
647static int perf_session_queue_event(struct perf_session *s, union perf_event *event, 646int 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
757static 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
758static void dump_event(struct perf_session *session, union perf_event *event, 787static 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
809static struct machine * 841static 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
864static 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
888static 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
908static int
909perf_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
831static int perf_session_deliver_event(struct perf_session *session, 933static 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
898static 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
914static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1002static 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
1000struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1082struct 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
1005static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1087static 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
1296bool perf_session__has_traces(struct perf_session *session, const char *msg) 1384bool 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
1306int maps__set_kallsyms_ref_reloc_sym(struct map **maps, 1397int 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
1384void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 1475void 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)