aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 56b2fb8135ce..971ff91b16cb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -21,6 +21,7 @@
21#include "util/cpumap.h" 21#include "util/cpumap.h"
22#include "util/thread_map.h" 22#include "util/thread_map.h"
23#include "util/stat.h" 23#include "util/stat.h"
24#include "util/thread-stack.h"
24#include <linux/bitmap.h> 25#include <linux/bitmap.h>
25#include <linux/stringify.h> 26#include <linux/stringify.h>
26#include "asm/bug.h" 27#include "asm/bug.h"
@@ -63,6 +64,7 @@ enum perf_output_field {
63 PERF_OUTPUT_DATA_SRC = 1U << 17, 64 PERF_OUTPUT_DATA_SRC = 1U << 17,
64 PERF_OUTPUT_WEIGHT = 1U << 18, 65 PERF_OUTPUT_WEIGHT = 1U << 18,
65 PERF_OUTPUT_BPF_OUTPUT = 1U << 19, 66 PERF_OUTPUT_BPF_OUTPUT = 1U << 19,
67 PERF_OUTPUT_CALLINDENT = 1U << 20,
66}; 68};
67 69
68struct output_option { 70struct output_option {
@@ -89,6 +91,7 @@ struct output_option {
89 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, 91 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
90 {.str = "weight", .field = PERF_OUTPUT_WEIGHT}, 92 {.str = "weight", .field = PERF_OUTPUT_WEIGHT},
91 {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT}, 93 {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT},
94 {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT},
92}; 95};
93 96
94/* default set to maintain compatibility with current format */ 97/* default set to maintain compatibility with current format */
@@ -562,6 +565,62 @@ static void print_sample_addr(struct perf_sample *sample,
562 } 565 }
563} 566}
564 567
568static void print_sample_callindent(struct perf_sample *sample,
569 struct perf_evsel *evsel,
570 struct thread *thread,
571 struct addr_location *al)
572{
573 struct perf_event_attr *attr = &evsel->attr;
574 size_t depth = thread_stack__depth(thread);
575 struct addr_location addr_al;
576 const char *name = NULL;
577 static int spacing;
578 int len = 0;
579 u64 ip = 0;
580
581 /*
582 * The 'return' has already been popped off the stack so the depth has
583 * to be adjusted to match the 'call'.
584 */
585 if (thread->ts && sample->flags & PERF_IP_FLAG_RETURN)
586 depth += 1;
587
588 if (sample->flags & (PERF_IP_FLAG_CALL | PERF_IP_FLAG_TRACE_BEGIN)) {
589 if (sample_addr_correlates_sym(attr)) {
590 thread__resolve(thread, &addr_al, sample);
591 if (addr_al.sym)
592 name = addr_al.sym->name;
593 else
594 ip = sample->addr;
595 } else {
596 ip = sample->addr;
597 }
598 } else if (sample->flags & (PERF_IP_FLAG_RETURN | PERF_IP_FLAG_TRACE_END)) {
599 if (al->sym)
600 name = al->sym->name;
601 else
602 ip = sample->ip;
603 }
604
605 if (name)
606 len = printf("%*s%s", (int)depth * 4, "", name);
607 else if (ip)
608 len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip);
609
610 if (len < 0)
611 return;
612
613 /*
614 * Try to keep the output length from changing frequently so that the
615 * output lines up more nicely.
616 */
617 if (len > spacing || (len && len < spacing - 52))
618 spacing = round_up(len + 4, 32);
619
620 if (len < spacing)
621 printf("%*s", spacing - len, "");
622}
623
565static void print_sample_bts(struct perf_sample *sample, 624static void print_sample_bts(struct perf_sample *sample,
566 struct perf_evsel *evsel, 625 struct perf_evsel *evsel,
567 struct thread *thread, 626 struct thread *thread,
@@ -570,6 +629,9 @@ static void print_sample_bts(struct perf_sample *sample,
570 struct perf_event_attr *attr = &evsel->attr; 629 struct perf_event_attr *attr = &evsel->attr;
571 bool print_srcline_last = false; 630 bool print_srcline_last = false;
572 631
632 if (PRINT_FIELD(CALLINDENT))
633 print_sample_callindent(sample, evsel, thread, al);
634
573 /* print branch_from information */ 635 /* print branch_from information */
574 if (PRINT_FIELD(IP)) { 636 if (PRINT_FIELD(IP)) {
575 unsigned int print_opts = output[attr->type].print_ip_opts; 637 unsigned int print_opts = output[attr->type].print_ip_opts;
@@ -2053,7 +2115,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2053 "comma separated output fields prepend with 'type:'. " 2115 "comma separated output fields prepend with 'type:'. "
2054 "Valid types: hw,sw,trace,raw. " 2116 "Valid types: hw,sw,trace,raw. "
2055 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," 2117 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
2056 "addr,symoff,period,iregs,brstack,brstacksym,flags", parse_output_fields), 2118 "addr,symoff,period,iregs,brstack,brstacksym,flags,"
2119 "callindent", parse_output_fields),
2057 OPT_BOOLEAN('a', "all-cpus", &system_wide, 2120 OPT_BOOLEAN('a', "all-cpus", &system_wide,
2058 "system-wide collection from all CPUs"), 2121 "system-wide collection from all CPUs"),
2059 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 2122 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
@@ -2292,6 +2355,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2292 script.session = session; 2355 script.session = session;
2293 script__setup_sample_type(&script); 2356 script__setup_sample_type(&script);
2294 2357
2358 if (output[PERF_TYPE_HARDWARE].fields & PERF_OUTPUT_CALLINDENT)
2359 itrace_synth_opts.thread_stack = true;
2360
2295 session->itrace_synth_opts = &itrace_synth_opts; 2361 session->itrace_synth_opts = &itrace_synth_opts;
2296 2362
2297 if (cpu_list) { 2363 if (cpu_list) {