mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
perf record/report: Add call graph / call chain profiling
Add the first steps of call-graph profiling: - add the -c (--call-graph) option to perf record - parse the call-graph record and printout out under -D (--dump-trace) The call-graph data is not put into the histogram yet, but it can be seen that it's being processed correctly: 0x3ce0 [0x38]: event: 35 . . ... raw event: size 56 bytes . 0000: 23 00 00 00 05 00 38 00 d4 df 0e 81 ff ff ff ff #.....8........ . 0010: 60 0b 00 00 60 0b 00 00 03 00 00 00 01 00 02 00 `...`.......... . 0020: d4 df 0e 81 ff ff ff ff a0 61 ed 41 36 00 00 00 .........a.A6.. . 0030: 04 92 e6 41 36 00 00 00 .a.A6.. . 0x3ce0 [0x38]: PERF_EVENT (IP, 5): 2912: 0xffffffff810edfd4 period: 1 ... chain: u:2, k:1, nr:3 ..... 0: 0xffffffff810edfd4 ..... 1: 0x3641ed61a0 ..... 2: 0x3641e69204 ... thread: perf:2912 ...... dso: [kernel] This shows a 3-entry call-graph: with 1 kernel-space and two user-space entries Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Pekka Enberg <penberg@cs.helsinki.fi> Cc: Arjan van de Ven <arjan@infradead.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
8465b05046
commit
3efa1cc99e
2 changed files with 53 additions and 12 deletions
|
@ -37,6 +37,7 @@ static pid_t target_pid = -1;
|
||||||
static int inherit = 1;
|
static int inherit = 1;
|
||||||
static int force = 0;
|
static int force = 0;
|
||||||
static int append_file = 0;
|
static int append_file = 0;
|
||||||
|
static int call_graph = 0;
|
||||||
static int verbose = 0;
|
static int verbose = 0;
|
||||||
|
|
||||||
static long samples;
|
static long samples;
|
||||||
|
@ -351,11 +352,16 @@ static void create_counter(int counter, int cpu, pid_t pid)
|
||||||
int track = 1;
|
int track = 1;
|
||||||
|
|
||||||
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
|
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
|
||||||
|
|
||||||
if (freq) {
|
if (freq) {
|
||||||
attr->sample_type |= PERF_SAMPLE_PERIOD;
|
attr->sample_type |= PERF_SAMPLE_PERIOD;
|
||||||
attr->freq = 1;
|
attr->freq = 1;
|
||||||
attr->sample_freq = freq;
|
attr->sample_freq = freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (call_graph)
|
||||||
|
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
|
||||||
|
|
||||||
attr->mmap = track;
|
attr->mmap = track;
|
||||||
attr->comm = track;
|
attr->comm = track;
|
||||||
attr->inherit = (cpu < 0) && inherit;
|
attr->inherit = (cpu < 0) && inherit;
|
||||||
|
@ -555,6 +561,8 @@ static const struct option options[] = {
|
||||||
"profile at this frequency"),
|
"profile at this frequency"),
|
||||||
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
|
OPT_INTEGER('m', "mmap-pages", &mmap_pages,
|
||||||
"number of mmap data pages"),
|
"number of mmap data pages"),
|
||||||
|
OPT_BOOLEAN('g', "call-graph", &call_graph,
|
||||||
|
"do call-graph (stack chain/backtrace) recording"),
|
||||||
OPT_BOOLEAN('v', "verbose", &verbose,
|
OPT_BOOLEAN('v', "verbose", &verbose,
|
||||||
"be more verbose (show counter open errors, etc)"),
|
"be more verbose (show counter open errors, etc)"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
|
|
|
@ -36,6 +36,7 @@ static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
|
||||||
|
|
||||||
static int dump_trace = 0;
|
static int dump_trace = 0;
|
||||||
#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
|
#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
|
||||||
|
#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
|
||||||
|
|
||||||
static int verbose;
|
static int verbose;
|
||||||
static int full_paths;
|
static int full_paths;
|
||||||
|
@ -43,11 +44,19 @@ static int full_paths;
|
||||||
static unsigned long page_size;
|
static unsigned long page_size;
|
||||||
static unsigned long mmap_window = 32;
|
static unsigned long mmap_window = 32;
|
||||||
|
|
||||||
|
struct ip_chain_event {
|
||||||
|
__u16 nr;
|
||||||
|
__u16 hv;
|
||||||
|
__u16 kernel;
|
||||||
|
__u16 user;
|
||||||
|
__u64 ips[];
|
||||||
|
};
|
||||||
|
|
||||||
struct ip_event {
|
struct ip_event {
|
||||||
struct perf_event_header header;
|
struct perf_event_header header;
|
||||||
__u64 ip;
|
__u64 ip;
|
||||||
__u32 pid, tid;
|
__u32 pid, tid;
|
||||||
__u64 period;
|
unsigned char __more_data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mmap_event {
|
struct mmap_event {
|
||||||
|
@ -944,9 +953,13 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
|
||||||
__u64 ip = event->ip.ip;
|
__u64 ip = event->ip.ip;
|
||||||
__u64 period = 1;
|
__u64 period = 1;
|
||||||
struct map *map = NULL;
|
struct map *map = NULL;
|
||||||
|
void *more_data = event->ip.__more_data;
|
||||||
|
struct ip_chain_event *chain;
|
||||||
|
|
||||||
if (event->header.type & PERF_SAMPLE_PERIOD)
|
if (event->header.type & PERF_SAMPLE_PERIOD) {
|
||||||
period = event->ip.period;
|
period = *(__u64 *)more_data;
|
||||||
|
more_data += sizeof(__u64);
|
||||||
|
}
|
||||||
|
|
||||||
dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n",
|
dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n",
|
||||||
(void *)(offset + head),
|
(void *)(offset + head),
|
||||||
|
@ -956,6 +969,22 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
|
||||||
(void *)(long)ip,
|
(void *)(long)ip,
|
||||||
(long long)period);
|
(long long)period);
|
||||||
|
|
||||||
|
if (event->header.type & PERF_SAMPLE_CALLCHAIN) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
chain = (void *)more_data;
|
||||||
|
|
||||||
|
if (dump_trace) {
|
||||||
|
dprintf("... chain: u:%d, k:%d, nr:%d\n",
|
||||||
|
chain->user,
|
||||||
|
chain->kernel,
|
||||||
|
chain->nr);
|
||||||
|
|
||||||
|
for (i = 0; i < chain->nr; i++)
|
||||||
|
dprintf("..... %2d: %p\n", i, (void *)chain->ips[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
|
dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
|
||||||
|
|
||||||
if (thread == NULL) {
|
if (thread == NULL) {
|
||||||
|
@ -1098,30 +1127,34 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head)
|
||||||
static void trace_event(event_t *event)
|
static void trace_event(event_t *event)
|
||||||
{
|
{
|
||||||
unsigned char *raw_event = (void *)event;
|
unsigned char *raw_event = (void *)event;
|
||||||
|
char *color = PERF_COLOR_BLUE;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if (!dump_trace)
|
if (!dump_trace)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dprintf(".\n. ... raw event: size %d bytes\n", event->header.size);
|
dprintf(".");
|
||||||
|
cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
|
||||||
|
|
||||||
for (i = 0; i < event->header.size; i++) {
|
for (i = 0; i < event->header.size; i++) {
|
||||||
if ((i & 15) == 0)
|
if ((i & 15) == 0) {
|
||||||
dprintf(". %04x: ", i);
|
dprintf(".");
|
||||||
|
cdprintf(" %04x: ", i);
|
||||||
|
}
|
||||||
|
|
||||||
dprintf(" %02x", raw_event[i]);
|
cdprintf(" %02x", raw_event[i]);
|
||||||
|
|
||||||
if (((i & 15) == 15) || i == event->header.size-1) {
|
if (((i & 15) == 15) || i == event->header.size-1) {
|
||||||
dprintf(" ");
|
cdprintf(" ");
|
||||||
for (j = 0; j < 15-(i & 15); j++)
|
for (j = 0; j < 15-(i & 15); j++)
|
||||||
dprintf(" ");
|
cdprintf(" ");
|
||||||
for (j = 0; j < (i & 15); j++) {
|
for (j = 0; j < (i & 15); j++) {
|
||||||
if (isprint(raw_event[i-15+j]))
|
if (isprint(raw_event[i-15+j]))
|
||||||
dprintf("%c", raw_event[i-15+j]);
|
cdprintf("%c", raw_event[i-15+j]);
|
||||||
else
|
else
|
||||||
dprintf(".");
|
cdprintf(".");
|
||||||
}
|
}
|
||||||
dprintf("\n");
|
cdprintf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dprintf(".\n");
|
dprintf(".\n");
|
||||||
|
|
Loading…
Reference in a new issue