diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 64 |
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 | ||
556 | static void callchain__printf(struct perf_sample *sample) | 556 | static 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 | |||
603 | static 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 | ||
567 | static void branch_stack__printf(struct perf_sample *sample) | 619 | static 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) |