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.c64
1 files changed, 58 insertions, 6 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0baf75f12b7c..504b7e664e6c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -553,15 +553,67 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,
553 return 0; 553 return 0;
554} 554}
555 555
556static void callchain__printf(struct perf_sample *sample) 556static void callchain__lbr_callstack_printf(struct perf_sample *sample)
557{ 557{
558 struct ip_callchain *callchain = sample->callchain;
559 struct branch_stack *lbr_stack = sample->branch_stack;
560 u64 kernel_callchain_nr = callchain->nr;
558 unsigned int i; 561 unsigned int i;
559 562
560 printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr); 563 for (i = 0; i < kernel_callchain_nr; i++) {
564 if (callchain->ips[i] == PERF_CONTEXT_USER)
565 break;
566 }
567
568 if ((i != kernel_callchain_nr) && lbr_stack->nr) {
569 u64 total_nr;
570 /*
571 * LBR callstack can only get user call chain,
572 * i is kernel call chain number,
573 * 1 is PERF_CONTEXT_USER.
574 *
575 * The user call chain is stored in LBR registers.
576 * LBR are pair registers. The caller is stored
577 * in "from" register, while the callee is stored
578 * in "to" register.
579 * For example, there is a call stack
580 * "A"->"B"->"C"->"D".
581 * The LBR registers will recorde like
582 * "C"->"D", "B"->"C", "A"->"B".
583 * So only the first "to" register and all "from"
584 * registers are needed to construct the whole stack.
585 */
586 total_nr = i + 1 + lbr_stack->nr + 1;
587 kernel_callchain_nr = i + 1;
588
589 printf("... LBR call chain: nr:%" PRIu64 "\n", total_nr);
590
591 for (i = 0; i < kernel_callchain_nr; i++)
592 printf("..... %2d: %016" PRIx64 "\n",
593 i, callchain->ips[i]);
594
595 printf("..... %2d: %016" PRIx64 "\n",
596 (int)(kernel_callchain_nr), lbr_stack->entries[0].to);
597 for (i = 0; i < lbr_stack->nr; i++)
598 printf("..... %2d: %016" PRIx64 "\n",
599 (int)(i + kernel_callchain_nr + 1), lbr_stack->entries[i].from);
600 }
601}
602
603static void callchain__printf(struct perf_evsel *evsel,
604 struct perf_sample *sample)
605{
606 unsigned int i;
607 struct ip_callchain *callchain = sample->callchain;
608
609 if (has_branch_callstack(evsel))
610 callchain__lbr_callstack_printf(sample);
611
612 printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr);
561 613
562 for (i = 0; i < sample->callchain->nr; i++) 614 for (i = 0; i < callchain->nr; i++)
563 printf("..... %2d: %016" PRIx64 "\n", 615 printf("..... %2d: %016" PRIx64 "\n",
564 i, sample->callchain->ips[i]); 616 i, callchain->ips[i]);
565} 617}
566 618
567static void branch_stack__printf(struct perf_sample *sample) 619static void branch_stack__printf(struct perf_sample *sample)
@@ -718,9 +770,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
718 sample_type = evsel->attr.sample_type; 770 sample_type = evsel->attr.sample_type;
719 771
720 if (sample_type & PERF_SAMPLE_CALLCHAIN) 772 if (sample_type & PERF_SAMPLE_CALLCHAIN)
721 callchain__printf(sample); 773 callchain__printf(evsel, sample);
722 774
723 if (sample_type & PERF_SAMPLE_BRANCH_STACK) 775 if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !has_branch_callstack(evsel))
724 branch_stack__printf(sample); 776 branch_stack__printf(sample);
725 777
726 if (sample_type & PERF_SAMPLE_REGS_USER) 778 if (sample_type & PERF_SAMPLE_REGS_USER)