mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-20 18:54:09 +08:00
perf script: Support -F brstackoff,dso
The idea here is to make AutoFDO easier in cloud environment with ASLR. It's easiest to show how this is useful by example. I built a small test akin to "while(1) { do_nothing(); }" where the do_nothing function is loaded from a dso: $ cat burncpu.cpp #include <dlfcn.h> int main() { void* handle = dlopen("./dso.so", RTLD_LAZY); if (!handle) return -1; typedef void (*fp)(); fp do_nothing = (fp) dlsym(handle, "do_nothing"); while(1) { do_nothing(); } } $ cat dso.cpp extern "C" void do_nothing() {} $ cat build.sh #!/bin/bash g++ -shared dso.cpp -o dso.so g++ burncpu.cpp -o burncpu -ldl I sampled the execution of this program with perf record -b. Using the existing "brstack,dso", we get absolute addresses that are affected by ASLR, and could be different on different hosts. The address does not uniquely identify a branch/target in the binary: $ perf script -F brstack,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 0x7f967139b6aa(/tmp/burncpu/dso.so)/0x4006b1(/tmp/burncpu/exe)/P/-/-/0 Using the existing "brstacksym,dso" is a little better, because the symbol plus offset and dso name *does* uniquely identify a branch/target in the binary. Ultimately, however, AutoFDO wants a simple offset into the binary, so we'd have to undo all the work perf did to symbolize in the first place: $ perf script -F brstacksym,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 do_nothing+0x5(/tmp/burncpu/dso.so)/main+0x44(/tmp/burncpu/exe)/P/-/-/0 With the new "brstackoff,dso" we get what we need: a simple offset into a specific dso/binary that uniquely identifies a branch/target: $ perf script -F brstackoff,dso | sed 's/\/0 /\/0\n/g' | grep burncpu | grep dso.so | head -n 1 0x6aa(/tmp/burncpu/dso.so)/0x4006b1(/tmp/burncpu/exe)/P/-/-/0 Signed-off-by: Mark Santaniello <marksan@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20170619163825.2012979-2-marksan@fb.com [ Updated documentation about 'brstackoff' using text from above ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
55b9b50811
commit
106dacd86f
@ -116,7 +116,7 @@ OPTIONS
|
|||||||
--fields::
|
--fields::
|
||||||
Comma separated list of fields to print. Options are:
|
Comma separated list of fields to print. Options are:
|
||||||
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
|
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
|
||||||
srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
|
srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff,
|
||||||
callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw,
|
callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw,
|
||||||
to indicate to which event type the field list applies.
|
to indicate to which event type the field list applies.
|
||||||
e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
|
e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
|
||||||
@ -211,6 +211,8 @@ OPTIONS
|
|||||||
is printed. This is the full execution path leading to the sample. This is only supported when the
|
is printed. This is the full execution path leading to the sample. This is only supported when the
|
||||||
sample was recorded with perf record -b or -j any.
|
sample was recorded with perf record -b or -j any.
|
||||||
|
|
||||||
|
The brstackoff field will print an offset into a specific dso/binary.
|
||||||
|
|
||||||
-k::
|
-k::
|
||||||
--vmlinux=<file>::
|
--vmlinux=<file>::
|
||||||
vmlinux pathname
|
vmlinux pathname
|
||||||
|
@ -85,6 +85,7 @@ enum perf_output_field {
|
|||||||
PERF_OUTPUT_INSN = 1U << 21,
|
PERF_OUTPUT_INSN = 1U << 21,
|
||||||
PERF_OUTPUT_INSNLEN = 1U << 22,
|
PERF_OUTPUT_INSNLEN = 1U << 22,
|
||||||
PERF_OUTPUT_BRSTACKINSN = 1U << 23,
|
PERF_OUTPUT_BRSTACKINSN = 1U << 23,
|
||||||
|
PERF_OUTPUT_BRSTACKOFF = 1U << 24,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output_option {
|
struct output_option {
|
||||||
@ -115,6 +116,7 @@ struct output_option {
|
|||||||
{.str = "insn", .field = PERF_OUTPUT_INSN},
|
{.str = "insn", .field = PERF_OUTPUT_INSN},
|
||||||
{.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},
|
{.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},
|
||||||
{.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN},
|
{.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN},
|
||||||
|
{.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* default set to maintain compatibility with current format */
|
/* default set to maintain compatibility with current format */
|
||||||
@ -299,10 +301,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) &&
|
if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) &&
|
||||||
!PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM)) {
|
!PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) {
|
||||||
pr_err("Display of DSO requested but none of sample IP, sample address, "
|
pr_err("Display of DSO requested but no address to convert. Select\n"
|
||||||
"brstack\nor brstacksym are selected. Hence, no addresses to "
|
"sample IP, sample address, brstack, brstacksym, or brstackoff.\n");
|
||||||
"convert to DSO.\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
|
if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
|
||||||
@ -606,6 +607,51 @@ static void print_sample_brstacksym(struct perf_sample *sample,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_sample_brstackoff(struct perf_sample *sample,
|
||||||
|
struct thread *thread,
|
||||||
|
struct perf_event_attr *attr)
|
||||||
|
{
|
||||||
|
struct branch_stack *br = sample->branch_stack;
|
||||||
|
struct addr_location alf, alt;
|
||||||
|
u64 i, from, to;
|
||||||
|
|
||||||
|
if (!(br && br->nr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < br->nr; i++) {
|
||||||
|
|
||||||
|
memset(&alf, 0, sizeof(alf));
|
||||||
|
memset(&alt, 0, sizeof(alt));
|
||||||
|
from = br->entries[i].from;
|
||||||
|
to = br->entries[i].to;
|
||||||
|
|
||||||
|
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
|
||||||
|
if (alf.map && !alf.map->dso->adjust_symbols)
|
||||||
|
from = map__map_ip(alf.map, from);
|
||||||
|
|
||||||
|
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
|
||||||
|
if (alt.map && !alt.map->dso->adjust_symbols)
|
||||||
|
to = map__map_ip(alt.map, to);
|
||||||
|
|
||||||
|
printf("0x%"PRIx64, from);
|
||||||
|
if (PRINT_FIELD(DSO)) {
|
||||||
|
printf("(");
|
||||||
|
map__fprintf_dsoname(alf.map, stdout);
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
printf("/0x%"PRIx64, to);
|
||||||
|
if (PRINT_FIELD(DSO)) {
|
||||||
|
printf("(");
|
||||||
|
map__fprintf_dsoname(alt.map, stdout);
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
printf("/%c/%c/%c/%d ",
|
||||||
|
mispred_str(br->entries + i),
|
||||||
|
br->entries[i].flags.in_tx ? 'X' : '-',
|
||||||
|
br->entries[i].flags.abort ? 'A' : '-',
|
||||||
|
br->entries[i].flags.cycles);
|
||||||
|
}
|
||||||
|
}
|
||||||
#define MAXBB 16384UL
|
#define MAXBB 16384UL
|
||||||
|
|
||||||
static int grab_bb(u8 *buffer, u64 start, u64 end,
|
static int grab_bb(u8 *buffer, u64 start, u64 end,
|
||||||
@ -1227,6 +1273,8 @@ static void process_event(struct perf_script *script,
|
|||||||
print_sample_brstack(sample, thread, attr);
|
print_sample_brstack(sample, thread, attr);
|
||||||
else if (PRINT_FIELD(BRSTACKSYM))
|
else if (PRINT_FIELD(BRSTACKSYM))
|
||||||
print_sample_brstacksym(sample, thread, attr);
|
print_sample_brstacksym(sample, thread, attr);
|
||||||
|
else if (PRINT_FIELD(BRSTACKOFF))
|
||||||
|
print_sample_brstackoff(sample, thread, attr);
|
||||||
|
|
||||||
if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
|
if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
|
||||||
print_sample_bpf_output(sample);
|
print_sample_bpf_output(sample);
|
||||||
|
Loading…
Reference in New Issue
Block a user