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.c198
1 files changed, 144 insertions, 54 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 2437fb0b463a..8cdd23239c90 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -15,6 +15,9 @@
15#include "util.h" 15#include "util.h"
16#include "cpumap.h" 16#include "cpumap.h"
17#include "event-parse.h" 17#include "event-parse.h"
18#include "perf_regs.h"
19#include "unwind.h"
20#include "vdso.h"
18 21
19static int perf_session__open(struct perf_session *self, bool force) 22static int perf_session__open(struct perf_session *self, bool force)
20{ 23{
@@ -209,6 +212,7 @@ void perf_session__delete(struct perf_session *self)
209 machine__exit(&self->host_machine); 212 machine__exit(&self->host_machine);
210 close(self->fd); 213 close(self->fd);
211 free(self); 214 free(self);
215 vdso__exit();
212} 216}
213 217
214void machine__remove_thread(struct machine *self, struct thread *th) 218void machine__remove_thread(struct machine *self, struct thread *th)
@@ -288,10 +292,11 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
288 return bi; 292 return bi;
289} 293}
290 294
291int machine__resolve_callchain(struct machine *self, 295static int machine__resolve_callchain_sample(struct machine *machine,
292 struct thread *thread, 296 struct thread *thread,
293 struct ip_callchain *chain, 297 struct ip_callchain *chain,
294 struct symbol **parent) 298 struct symbol **parent)
299
295{ 300{
296 u8 cpumode = PERF_RECORD_MISC_USER; 301 u8 cpumode = PERF_RECORD_MISC_USER;
297 unsigned int i; 302 unsigned int i;
@@ -316,11 +321,14 @@ int machine__resolve_callchain(struct machine *self,
316 if (ip >= PERF_CONTEXT_MAX) { 321 if (ip >= PERF_CONTEXT_MAX) {
317 switch (ip) { 322 switch (ip) {
318 case PERF_CONTEXT_HV: 323 case PERF_CONTEXT_HV:
319 cpumode = PERF_RECORD_MISC_HYPERVISOR; break; 324 cpumode = PERF_RECORD_MISC_HYPERVISOR;
325 break;
320 case PERF_CONTEXT_KERNEL: 326 case PERF_CONTEXT_KERNEL:
321 cpumode = PERF_RECORD_MISC_KERNEL; break; 327 cpumode = PERF_RECORD_MISC_KERNEL;
328 break;
322 case PERF_CONTEXT_USER: 329 case PERF_CONTEXT_USER:
323 cpumode = PERF_RECORD_MISC_USER; break; 330 cpumode = PERF_RECORD_MISC_USER;
331 break;
324 default: 332 default:
325 pr_debug("invalid callchain context: " 333 pr_debug("invalid callchain context: "
326 "%"PRId64"\n", (s64) ip); 334 "%"PRId64"\n", (s64) ip);
@@ -335,7 +343,7 @@ int machine__resolve_callchain(struct machine *self,
335 } 343 }
336 344
337 al.filtered = false; 345 al.filtered = false;
338 thread__find_addr_location(thread, self, cpumode, 346 thread__find_addr_location(thread, machine, cpumode,
339 MAP__FUNCTION, ip, &al, NULL); 347 MAP__FUNCTION, ip, &al, NULL);
340 if (al.sym != NULL) { 348 if (al.sym != NULL) {
341 if (sort__has_parent && !*parent && 349 if (sort__has_parent && !*parent &&
@@ -354,49 +362,92 @@ int machine__resolve_callchain(struct machine *self,
354 return 0; 362 return 0;
355} 363}
356 364
357static int process_event_synth_tracing_data_stub(union perf_event *event __used, 365static int unwind_entry(struct unwind_entry *entry, void *arg)
358 struct perf_session *session __used) 366{
367 struct callchain_cursor *cursor = arg;
368 return callchain_cursor_append(cursor, entry->ip,
369 entry->map, entry->sym);
370}
371
372int machine__resolve_callchain(struct machine *machine,
373 struct perf_evsel *evsel,
374 struct thread *thread,
375 struct perf_sample *sample,
376 struct symbol **parent)
377
378{
379 int ret;
380
381 callchain_cursor_reset(&callchain_cursor);
382
383 ret = machine__resolve_callchain_sample(machine, thread,
384 sample->callchain, parent);
385 if (ret)
386 return ret;
387
388 /* Can we do dwarf post unwind? */
389 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
390 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
391 return 0;
392
393 /* Bail out if nothing was captured. */
394 if ((!sample->user_regs.regs) ||
395 (!sample->user_stack.size))
396 return 0;
397
398 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
399 thread, evsel->attr.sample_regs_user,
400 sample);
401
402}
403
404static int process_event_synth_tracing_data_stub(union perf_event *event
405 __maybe_unused,
406 struct perf_session *session
407 __maybe_unused)
359{ 408{
360 dump_printf(": unhandled!\n"); 409 dump_printf(": unhandled!\n");
361 return 0; 410 return 0;
362} 411}
363 412
364static int process_event_synth_attr_stub(union perf_event *event __used, 413static int process_event_synth_attr_stub(union perf_event *event __maybe_unused,
365 struct perf_evlist **pevlist __used) 414 struct perf_evlist **pevlist
415 __maybe_unused)
366{ 416{
367 dump_printf(": unhandled!\n"); 417 dump_printf(": unhandled!\n");
368 return 0; 418 return 0;
369} 419}
370 420
371static int process_event_sample_stub(struct perf_tool *tool __used, 421static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
372 union perf_event *event __used, 422 union perf_event *event __maybe_unused,
373 struct perf_sample *sample __used, 423 struct perf_sample *sample __maybe_unused,
374 struct perf_evsel *evsel __used, 424 struct perf_evsel *evsel __maybe_unused,
375 struct machine *machine __used) 425 struct machine *machine __maybe_unused)
376{ 426{
377 dump_printf(": unhandled!\n"); 427 dump_printf(": unhandled!\n");
378 return 0; 428 return 0;
379} 429}
380 430
381static int process_event_stub(struct perf_tool *tool __used, 431static int process_event_stub(struct perf_tool *tool __maybe_unused,
382 union perf_event *event __used, 432 union perf_event *event __maybe_unused,
383 struct perf_sample *sample __used, 433 struct perf_sample *sample __maybe_unused,
384 struct machine *machine __used) 434 struct machine *machine __maybe_unused)
385{ 435{
386 dump_printf(": unhandled!\n"); 436 dump_printf(": unhandled!\n");
387 return 0; 437 return 0;
388} 438}
389 439
390static int process_finished_round_stub(struct perf_tool *tool __used, 440static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
391 union perf_event *event __used, 441 union perf_event *event __maybe_unused,
392 struct perf_session *perf_session __used) 442 struct perf_session *perf_session
443 __maybe_unused)
393{ 444{
394 dump_printf(": unhandled!\n"); 445 dump_printf(": unhandled!\n");
395 return 0; 446 return 0;
396} 447}
397 448
398static int process_event_type_stub(struct perf_tool *tool __used, 449static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
399 union perf_event *event __used) 450 union perf_event *event __maybe_unused)
400{ 451{
401 dump_printf(": unhandled!\n"); 452 dump_printf(": unhandled!\n");
402 return 0; 453 return 0;
@@ -473,7 +524,7 @@ static void swap_sample_id_all(union perf_event *event, void *data)
473} 524}
474 525
475static void perf_event__all64_swap(union perf_event *event, 526static void perf_event__all64_swap(union perf_event *event,
476 bool sample_id_all __used) 527 bool sample_id_all __maybe_unused)
477{ 528{
478 struct perf_event_header *hdr = &event->header; 529 struct perf_event_header *hdr = &event->header;
479 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); 530 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
@@ -487,7 +538,7 @@ static void perf_event__comm_swap(union perf_event *event, bool sample_id_all)
487 if (sample_id_all) { 538 if (sample_id_all) {
488 void *data = &event->comm.comm; 539 void *data = &event->comm.comm;
489 540
490 data += ALIGN(strlen(data) + 1, sizeof(u64)); 541 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
491 swap_sample_id_all(event, data); 542 swap_sample_id_all(event, data);
492 } 543 }
493} 544}
@@ -504,7 +555,7 @@ static void perf_event__mmap_swap(union perf_event *event,
504 if (sample_id_all) { 555 if (sample_id_all) {
505 void *data = &event->mmap.filename; 556 void *data = &event->mmap.filename;
506 557
507 data += ALIGN(strlen(data) + 1, sizeof(u64)); 558 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
508 swap_sample_id_all(event, data); 559 swap_sample_id_all(event, data);
509 } 560 }
510} 561}
@@ -584,7 +635,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
584} 635}
585 636
586static void perf_event__hdr_attr_swap(union perf_event *event, 637static void perf_event__hdr_attr_swap(union perf_event *event,
587 bool sample_id_all __used) 638 bool sample_id_all __maybe_unused)
588{ 639{
589 size_t size; 640 size_t size;
590 641
@@ -596,14 +647,14 @@ static void perf_event__hdr_attr_swap(union perf_event *event,
596} 647}
597 648
598static void perf_event__event_type_swap(union perf_event *event, 649static void perf_event__event_type_swap(union perf_event *event,
599 bool sample_id_all __used) 650 bool sample_id_all __maybe_unused)
600{ 651{
601 event->event_type.event_type.event_id = 652 event->event_type.event_type.event_id =
602 bswap_64(event->event_type.event_type.event_id); 653 bswap_64(event->event_type.event_type.event_id);
603} 654}
604 655
605static void perf_event__tracing_data_swap(union perf_event *event, 656static void perf_event__tracing_data_swap(union perf_event *event,
606 bool sample_id_all __used) 657 bool sample_id_all __maybe_unused)
607{ 658{
608 event->tracing_data.size = bswap_32(event->tracing_data.size); 659 event->tracing_data.size = bswap_32(event->tracing_data.size);
609} 660}
@@ -652,7 +703,7 @@ static int perf_session_deliver_event(struct perf_session *session,
652 struct perf_tool *tool, 703 struct perf_tool *tool,
653 u64 file_offset); 704 u64 file_offset);
654 705
655static void flush_sample_queue(struct perf_session *s, 706static int flush_sample_queue(struct perf_session *s,
656 struct perf_tool *tool) 707 struct perf_tool *tool)
657{ 708{
658 struct ordered_samples *os = &s->ordered_samples; 709 struct ordered_samples *os = &s->ordered_samples;
@@ -665,19 +716,21 @@ static void flush_sample_queue(struct perf_session *s,
665 int ret; 716 int ret;
666 717
667 if (!tool->ordered_samples || !limit) 718 if (!tool->ordered_samples || !limit)
668 return; 719 return 0;
669 720
670 list_for_each_entry_safe(iter, tmp, head, list) { 721 list_for_each_entry_safe(iter, tmp, head, list) {
671 if (iter->timestamp > limit) 722 if (iter->timestamp > limit)
672 break; 723 break;
673 724
674 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample, 725 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
675 s->header.needs_swap);
676 if (ret) 726 if (ret)
677 pr_err("Can't parse sample, err = %d\n", ret); 727 pr_err("Can't parse sample, err = %d\n", ret);
678 else 728 else {
679 perf_session_deliver_event(s, iter->event, &sample, tool, 729 ret = perf_session_deliver_event(s, iter->event, &sample, tool,
680 iter->file_offset); 730 iter->file_offset);
731 if (ret)
732 return ret;
733 }
681 734
682 os->last_flush = iter->timestamp; 735 os->last_flush = iter->timestamp;
683 list_del(&iter->list); 736 list_del(&iter->list);
@@ -697,6 +750,8 @@ static void flush_sample_queue(struct perf_session *s,
697 } 750 }
698 751
699 os->nr_samples = 0; 752 os->nr_samples = 0;
753
754 return 0;
700} 755}
701 756
702/* 757/*
@@ -739,13 +794,14 @@ static void flush_sample_queue(struct perf_session *s,
739 * etc... 794 * etc...
740 */ 795 */
741static int process_finished_round(struct perf_tool *tool, 796static int process_finished_round(struct perf_tool *tool,
742 union perf_event *event __used, 797 union perf_event *event __maybe_unused,
743 struct perf_session *session) 798 struct perf_session *session)
744{ 799{
745 flush_sample_queue(session, tool); 800 int ret = flush_sample_queue(session, tool);
746 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; 801 if (!ret)
802 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
747 803
748 return 0; 804 return ret;
749} 805}
750 806
751/* The queue is ordered by time */ 807/* The queue is ordered by time */
@@ -860,6 +916,34 @@ static void branch_stack__printf(struct perf_sample *sample)
860 sample->branch_stack->entries[i].to); 916 sample->branch_stack->entries[i].to);
861} 917}
862 918
919static void regs_dump__printf(u64 mask, u64 *regs)
920{
921 unsigned rid, i = 0;
922
923 for_each_set_bit(rid, (unsigned long *) &mask, sizeof(mask) * 8) {
924 u64 val = regs[i++];
925
926 printf(".... %-5s 0x%" PRIx64 "\n",
927 perf_reg_name(rid), val);
928 }
929}
930
931static void regs_user__printf(struct perf_sample *sample, u64 mask)
932{
933 struct regs_dump *user_regs = &sample->user_regs;
934
935 if (user_regs->regs) {
936 printf("... user regs: mask 0x%" PRIx64 "\n", mask);
937 regs_dump__printf(mask, user_regs->regs);
938 }
939}
940
941static void stack_user__printf(struct stack_dump *dump)
942{
943 printf("... ustack: size %" PRIu64 ", offset 0x%x\n",
944 dump->size, dump->offset);
945}
946
863static void perf_session__print_tstamp(struct perf_session *session, 947static void perf_session__print_tstamp(struct perf_session *session,
864 union perf_event *event, 948 union perf_event *event,
865 struct perf_sample *sample) 949 struct perf_sample *sample)
@@ -897,7 +981,7 @@ static void dump_event(struct perf_session *session, union perf_event *event,
897 event->header.size, perf_event__name(event->header.type)); 981 event->header.size, perf_event__name(event->header.type));
898} 982}
899 983
900static void dump_sample(struct perf_session *session, union perf_event *event, 984static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
901 struct perf_sample *sample) 985 struct perf_sample *sample)
902{ 986{
903 u64 sample_type; 987 u64 sample_type;
@@ -909,13 +993,19 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
909 event->header.misc, sample->pid, sample->tid, sample->ip, 993 event->header.misc, sample->pid, sample->tid, sample->ip,
910 sample->period, sample->addr); 994 sample->period, sample->addr);
911 995
912 sample_type = perf_evlist__sample_type(session->evlist); 996 sample_type = evsel->attr.sample_type;
913 997
914 if (sample_type & PERF_SAMPLE_CALLCHAIN) 998 if (sample_type & PERF_SAMPLE_CALLCHAIN)
915 callchain__printf(sample); 999 callchain__printf(sample);
916 1000
917 if (sample_type & PERF_SAMPLE_BRANCH_STACK) 1001 if (sample_type & PERF_SAMPLE_BRANCH_STACK)
918 branch_stack__printf(sample); 1002 branch_stack__printf(sample);
1003
1004 if (sample_type & PERF_SAMPLE_REGS_USER)
1005 regs_user__printf(sample, evsel->attr.sample_regs_user);
1006
1007 if (sample_type & PERF_SAMPLE_STACK_USER)
1008 stack_user__printf(&sample->user_stack);
919} 1009}
920 1010
921static struct machine * 1011static struct machine *
@@ -973,7 +1063,7 @@ static int perf_session_deliver_event(struct perf_session *session,
973 1063
974 switch (event->header.type) { 1064 switch (event->header.type) {
975 case PERF_RECORD_SAMPLE: 1065 case PERF_RECORD_SAMPLE:
976 dump_sample(session, event, sample); 1066 dump_sample(evsel, event, sample);
977 if (evsel == NULL) { 1067 if (evsel == NULL) {
978 ++session->hists.stats.nr_unknown_id; 1068 ++session->hists.stats.nr_unknown_id;
979 return 0; 1069 return 0;
@@ -1083,8 +1173,7 @@ static int perf_session__process_event(struct perf_session *session,
1083 /* 1173 /*
1084 * For all kernel events we get the sample data 1174 * For all kernel events we get the sample data
1085 */ 1175 */
1086 ret = perf_evlist__parse_sample(session->evlist, event, &sample, 1176 ret = perf_evlist__parse_sample(session->evlist, event, &sample);
1087 session->header.needs_swap);
1088 if (ret) 1177 if (ret)
1089 return ret; 1178 return ret;
1090 1179
@@ -1369,7 +1458,7 @@ more:
1369 err = 0; 1458 err = 0;
1370 /* do the final flush for ordered samples */ 1459 /* do the final flush for ordered samples */
1371 session->ordered_samples.next_flush = ULLONG_MAX; 1460 session->ordered_samples.next_flush = ULLONG_MAX;
1372 flush_sample_queue(session, tool); 1461 err = flush_sample_queue(session, tool);
1373out_err: 1462out_err:
1374 perf_session__warn_about_errors(session, tool); 1463 perf_session__warn_about_errors(session, tool);
1375 perf_session_free_sample_buffers(session); 1464 perf_session_free_sample_buffers(session);
@@ -1498,9 +1587,9 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1498 return NULL; 1587 return NULL;
1499} 1588}
1500 1589
1501void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 1590void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1502 struct machine *machine, int print_sym, 1591 struct perf_sample *sample, struct machine *machine,
1503 int print_dso, int print_symoffset) 1592 int print_sym, int print_dso, int print_symoffset)
1504{ 1593{
1505 struct addr_location al; 1594 struct addr_location al;
1506 struct callchain_cursor_node *node; 1595 struct callchain_cursor_node *node;
@@ -1514,8 +1603,9 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1514 1603
1515 if (symbol_conf.use_callchain && sample->callchain) { 1604 if (symbol_conf.use_callchain && sample->callchain) {
1516 1605
1517 if (machine__resolve_callchain(machine, al.thread, 1606
1518 sample->callchain, NULL) != 0) { 1607 if (machine__resolve_callchain(machine, evsel, al.thread,
1608 sample, NULL) != 0) {
1519 if (verbose) 1609 if (verbose)
1520 error("Failed to resolve callchain. Skipping\n"); 1610 error("Failed to resolve callchain. Skipping\n");
1521 return; 1611 return;