Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3efa1cc9 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

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: default avatarIngo Molnar <mingo@elte.hu>
parent 8465b050
Loading
Loading
Loading
Loading
+8 −0
Original line number Original line Diff line number Diff line
@@ -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()
+45 −12
Original line number Original line Diff line number Diff line
@@ -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");