Skip to content

Commit 6f680c6

Browse files
Kan Liangacmel
authored andcommitted
perf script: Add 'brstackinsnlen' for branch stacks
When analyzing with 'perf script', it's useful to understand the captured instruction and the next sequential instruction. To calculate the address of the next sequential instruction, the length of the captured instruction is required. For example, you can’t know the next sequential instruction after an unconditional branch unless you calculate that based on its length. For branch stacks, 'perf script' only prints the instruction bytes with 'brstackinsn', but lacks the instruction length. Add 'brstackinsnlen' to print the instruction length. $ perf script -F ip,brstackinsn,brstackinsnlen --xed 7fa555be8f75 _start: 00007fa555be8090 mov %rsp, %rdi ilen: 3 00007fa555be8093 callq 0x7fa555be8ea0 ilen: 5 # PRED 102 cycles [102] 0.02 IPC _dl_start+38: 00007fa555be8ec6 movq %rdx,0x227853(%rip) ilen: 7 00007fa555be8ecd leaq 0x227f94(%rip),%rdx ilen: 7 Signed-off-by: Kan Liang <kan.liang@linux.intel.com> Cc: Ahmad Yasin <ahmad.yasin@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com> Link: https://lore.kernel.org/r/1647871212-184070-1-git-send-email-kan.liang@linux.intel.com [ Added the new field to tools/perf/Documentation/perf-script.txt ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent bc35582 commit 6f680c6

2 files changed

Lines changed: 38 additions & 14 deletions

File tree

tools/perf/Documentation/perf-script.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ OPTIONS
129129
Comma separated list of fields to print. Options are:
130130
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
131131
srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output,
132-
brstackinsn, brstackoff, callindent, insn, insnlen, synth, phys_addr,
133-
metric, misc, srccode, ipc, data_page_size, code_page_size, ins_lat.
132+
brstackinsn, brstackinsnlen, brstackoff, callindent, insn, insnlen, synth,
133+
phys_addr, metric, misc, srccode, ipc, data_page_size, code_page_size, ins_lat.
134134
Field list can be prepended with the type, trace, sw or hw,
135135
to indicate to which event type the field list applies.
136136
e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
@@ -241,6 +241,10 @@ OPTIONS
241241
is printed. This is the full execution path leading to the sample. This is only supported when the
242242
sample was recorded with perf record -b or -j any.
243243

244+
Use brstackinsnlen to print the brstackinsn lenght. For example, you
245+
can’t know the next sequential instruction after an unconditional branch unless
246+
you calculate that based on its length.
247+
244248
The brstackoff field will print an offset into a specific dso/binary.
245249

246250
With the metric option perf script can compute metrics for

tools/perf/builtin-script.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ enum perf_output_field {
124124
PERF_OUTPUT_DATA_PAGE_SIZE = 1ULL << 33,
125125
PERF_OUTPUT_CODE_PAGE_SIZE = 1ULL << 34,
126126
PERF_OUTPUT_INS_LAT = 1ULL << 35,
127+
PERF_OUTPUT_BRSTACKINSNLEN = 1ULL << 36,
127128
};
128129

129130
struct perf_script {
@@ -191,6 +192,7 @@ struct output_option {
191192
{.str = "data_page_size", .field = PERF_OUTPUT_DATA_PAGE_SIZE},
192193
{.str = "code_page_size", .field = PERF_OUTPUT_CODE_PAGE_SIZE},
193194
{.str = "ins_lat", .field = PERF_OUTPUT_INS_LAT},
195+
{.str = "brstackinsnlen", .field = PERF_OUTPUT_BRSTACKINSNLEN},
194196
};
195197

196198
enum {
@@ -488,7 +490,7 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
488490
"selected. Hence, no address to lookup the source line number.\n");
489491
return -EINVAL;
490492
}
491-
if (PRINT_FIELD(BRSTACKINSN) && !allow_user_set &&
493+
if ((PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN)) && !allow_user_set &&
492494
!(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) {
493495
pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"
494496
"Hint: run 'perf record -b ...'\n");
@@ -1120,10 +1122,17 @@ static int print_srccode(struct thread *thread, u8 cpumode, uint64_t addr)
11201122

11211123
static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
11221124
struct perf_insn *x, u8 *inbuf, int len,
1123-
int insn, FILE *fp, int *total_cycles)
1125+
int insn, FILE *fp, int *total_cycles,
1126+
struct perf_event_attr *attr)
11241127
{
1125-
int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip,
1126-
dump_insn(x, ip, inbuf, len, NULL),
1128+
int ilen = 0;
1129+
int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t", ip,
1130+
dump_insn(x, ip, inbuf, len, &ilen));
1131+
1132+
if (PRINT_FIELD(BRSTACKINSNLEN))
1133+
printed += fprintf(fp, "ilen: %d\t", ilen);
1134+
1135+
printed += fprintf(fp, "#%s%s%s%s",
11271136
en->flags.predicted ? " PRED" : "",
11281137
en->flags.mispred ? " MISPRED" : "",
11291138
en->flags.in_tx ? " INTX" : "",
@@ -1209,7 +1218,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
12091218
printed += ip__fprintf_sym(entries[nr - 1].from, thread,
12101219
x.cpumode, x.cpu, &lastsym, attr, fp);
12111220
printed += ip__fprintf_jump(entries[nr - 1].from, &entries[nr - 1],
1212-
&x, buffer, len, 0, fp, &total_cycles);
1221+
&x, buffer, len, 0, fp, &total_cycles,
1222+
attr);
12131223
if (PRINT_FIELD(SRCCODE))
12141224
printed += print_srccode(thread, x.cpumode, entries[nr - 1].from);
12151225
}
@@ -1240,14 +1250,17 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
12401250
printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
12411251
if (ip == end) {
12421252
printed += ip__fprintf_jump(ip, &entries[i], &x, buffer + off, len - off, ++insn, fp,
1243-
&total_cycles);
1253+
&total_cycles, attr);
12441254
if (PRINT_FIELD(SRCCODE))
12451255
printed += print_srccode(thread, x.cpumode, ip);
12461256
break;
12471257
} else {
12481258
ilen = 0;
1249-
printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip,
1259+
printed += fprintf(fp, "\t%016" PRIx64 "\t%s", ip,
12501260
dump_insn(&x, ip, buffer + off, len - off, &ilen));
1261+
if (PRINT_FIELD(BRSTACKINSNLEN))
1262+
printed += fprintf(fp, "\tilen: %d", ilen);
1263+
printed += fprintf(fp, "\n");
12511264
if (ilen == 0)
12521265
break;
12531266
if (PRINT_FIELD(SRCCODE))
@@ -1290,16 +1303,23 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
12901303
machine, thread, &x.is64bit, &x.cpumode, false);
12911304
if (len <= 0)
12921305
goto out;
1293-
printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip,
1294-
dump_insn(&x, sample->ip, buffer, len, NULL));
1306+
ilen = 0;
1307+
printed += fprintf(fp, "\t%016" PRIx64 "\t%s", sample->ip,
1308+
dump_insn(&x, sample->ip, buffer, len, &ilen));
1309+
if (PRINT_FIELD(BRSTACKINSNLEN))
1310+
printed += fprintf(fp, "\tilen: %d", ilen);
1311+
printed += fprintf(fp, "\n");
12951312
if (PRINT_FIELD(SRCCODE))
12961313
print_srccode(thread, x.cpumode, sample->ip);
12971314
goto out;
12981315
}
12991316
for (off = 0; off <= end - start; off += ilen) {
13001317
ilen = 0;
1301-
printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off,
1318+
printed += fprintf(fp, "\t%016" PRIx64 "\t%s", start + off,
13021319
dump_insn(&x, start + off, buffer + off, len - off, &ilen));
1320+
if (PRINT_FIELD(BRSTACKINSNLEN))
1321+
printed += fprintf(fp, "\tilen: %d", ilen);
1322+
printed += fprintf(fp, "\n");
13031323
if (ilen == 0)
13041324
break;
13051325
if (arch_is_branch(buffer + off, len - off, x.is64bit) && start + off != sample->ip) {
@@ -1457,7 +1477,7 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample,
14571477
for (i = 0; i < sample->insn_len; i++)
14581478
printed += fprintf(fp, " %02x", (unsigned char)sample->insn[i]);
14591479
}
1460-
if (PRINT_FIELD(BRSTACKINSN))
1480+
if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN))
14611481
printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp);
14621482

14631483
return printed;
@@ -3776,7 +3796,7 @@ int cmd_script(int argc, const char **argv)
37763796
"Valid types: hw,sw,trace,raw,synth. "
37773797
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
37783798
"addr,symoff,srcline,period,iregs,uregs,brstack,"
3779-
"brstacksym,flags,bpf-output,brstackinsn,brstackoff,"
3799+
"brstacksym,flags,bpf-output,brstackinsn,brstackinsnlen,brstackoff,"
37803800
"callindent,insn,insnlen,synth,phys_addr,metric,misc,ipc,tod,"
37813801
"data_page_size,code_page_size,ins_lat",
37823802
parse_output_fields),

0 commit comments

Comments
 (0)