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

Commit 971738f3 authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar
Browse files

perf annotate: Print a sorted summary of annotated overhead lines



It's can be very annoying to scroll down perf annotated output
until we find relevant overhead.

Using the -l option, you can now have a small summary sorted per
overhead in the beginning of the output.

Example:

./perf annotate -l -k ../../vmlinux -s __lock_acquire

Sorted summary for file ../../vmlinux
----------------------------------------------

   12.04 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1653
    4.61 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1740
    3.77 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1775
    3.56 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1653
    2.93 /home/fweisbec/linux/linux-2.6-tip/arch/x86/include/asm/irqflags.h:15
    2.83 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2545
    2.30 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2594
    2.20 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2388
    2.20 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:730
    2.09 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:730
    2.09 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:138
    1.88 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2548
    1.47 /home/fweisbec/linux/linux-2.6-tip/arch/x86/include/asm/irqflags.h:15
    1.36 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2594
    1.36 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:730
    1.26 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1654
    1.26 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1653
    1.15 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:2592
    1.15 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1740
    1.15 /home/fweisbec/linux/linux-2.6-tip/kernel/lockdep.c:1740

[...]

Only overhead over 0.5% are summarized.

Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1244844682-12928-2-git-send-email-fweisbec@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 301406b9
Loading
Loading
Loading
Loading
+90 −21
Original line number Original line Diff line number Diff line
@@ -25,6 +25,10 @@
#define SHOW_USER	2
#define SHOW_USER	2
#define SHOW_HV		4
#define SHOW_HV		4


#define MIN_GREEN		0.5
#define MIN_RED		5.0


static char		const *input_name = "perf.data";
static char		const *input_name = "perf.data";
static char		*vmlinux = "vmlinux";
static char		*vmlinux = "vmlinux";


@@ -88,6 +92,7 @@ typedef union event_union {




struct sym_ext {
struct sym_ext {
	struct rb_node	node;
	double		percent;
	double		percent;
	char		*path;
	char		*path;
};
};
@@ -1038,6 +1043,24 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
	return 0;
	return 0;
}
}


static char *get_color(double percent)
{
	char *color = PERF_COLOR_NORMAL;

	/*
	 * We color high-overhead entries in red, mid-overhead
	 * entries in green - and keep the low overhead places
	 * normal:
	 */
	if (percent >= MIN_RED)
		color = PERF_COLOR_RED;
	else {
		if (percent > MIN_GREEN)
			color = PERF_COLOR_GREEN;
	}
	return color;
}

static int
static int
parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
{
{
@@ -1086,7 +1109,7 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
		const char *path = NULL;
		const char *path = NULL;
		unsigned int hits = 0;
		unsigned int hits = 0;
		double percent = 0.0;
		double percent = 0.0;
		char *color = PERF_COLOR_NORMAL;
		char *color;
		struct sym_ext *sym_ext = sym->priv;
		struct sym_ext *sym_ext = sym->priv;


		offset = line_ip - start;
		offset = line_ip - start;
@@ -1099,17 +1122,7 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
		} else if (sym->hist_sum)
		} else if (sym->hist_sum)
			percent = 100.0 * hits / sym->hist_sum;
			percent = 100.0 * hits / sym->hist_sum;


		/*
		color = get_color(percent);
		 * We color high-overhead entries in red, mid-overhead
		 * entries in green - and keep the low overhead places
		 * normal:
		 */
		if (percent >= 5.0)
			color = PERF_COLOR_RED;
		else {
			if (percent > 0.5)
				color = PERF_COLOR_GREEN;
		}


		/*
		/*
		 * Also color the filename and line if needed, with
		 * Also color the filename and line if needed, with
@@ -1138,6 +1151,28 @@ parse_line(FILE *file, struct symbol *sym, __u64 start, __u64 len)
	return 0;
	return 0;
}
}


static struct rb_root root_sym_ext;

static void insert_source_line(struct sym_ext *sym_ext)
{
	struct sym_ext *iter;
	struct rb_node **p = &root_sym_ext.rb_node;
	struct rb_node *parent = NULL;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct sym_ext, node);

		if (sym_ext->percent > iter->percent)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&sym_ext->node, parent, p);
	rb_insert_color(&sym_ext->node, &root_sym_ext);
}

static void free_source_line(struct symbol *sym, int len)
static void free_source_line(struct symbol *sym, int len)
{
{
	struct sym_ext *sym_ext = sym->priv;
	struct sym_ext *sym_ext = sym->priv;
@@ -1151,6 +1186,7 @@ static void free_source_line(struct symbol *sym, int len)
	free(sym_ext);
	free(sym_ext);


	sym->priv = NULL;
	sym->priv = NULL;
	root_sym_ext = RB_ROOT;
}
}


/* Get the filename:line for the colored entries */
/* Get the filename:line for the colored entries */
@@ -1193,12 +1229,42 @@ static void get_source_line(struct symbol *sym, __u64 start, int len)
			goto next;
			goto next;


		strcpy(sym_ext[i].path, path);
		strcpy(sym_ext[i].path, path);
		insert_source_line(&sym_ext[i]);


	next:
	next:
		pclose(fp);
		pclose(fp);
	}
	}
}
}


static void print_summary(char *filename)
{
	struct sym_ext *sym_ext;
	struct rb_node *node;

	printf("\nSorted summary for file %s\n", filename);
	printf("----------------------------------------------\n\n");

	if (RB_EMPTY_ROOT(&root_sym_ext)) {
		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
		return;
	}

	node = rb_first(&root_sym_ext);
	while (node) {
		double percent;
		char *color;
		char *path;

		sym_ext = rb_entry(node, struct sym_ext, node);
		percent = sym_ext->percent;
		color = get_color(percent);
		path = sym_ext->path;

		color_fprintf(stdout, color, " %7.2f %s", percent, path);
		node = rb_next(node);
	}
}

static void annotate_sym(struct dso *dso, struct symbol *sym)
static void annotate_sym(struct dso *dso, struct symbol *sym)
{
{
	char *filename = dso->name;
	char *filename = dso->name;
@@ -1211,13 +1277,6 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
	if (dso == kernel_dso)
	if (dso == kernel_dso)
		filename = vmlinux;
		filename = vmlinux;


	printf("\n------------------------------------------------\n");
	printf(" Percent |	Source code & Disassembly of %s\n", filename);
	printf("------------------------------------------------\n");

	if (verbose >= 2)
		printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);

	start = sym->obj_start;
	start = sym->obj_start;
	if (!start)
	if (!start)
		start = sym->start;
		start = sym->start;
@@ -1225,8 +1284,17 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
	end = start + sym->end - sym->start + 1;
	end = start + sym->end - sym->start + 1;
	len = sym->end - sym->start;
	len = sym->end - sym->start;


	if (print_line)
	if (print_line) {
		get_source_line(sym, start, len);
		get_source_line(sym, start, len);
		print_summary(filename);
	}

	printf("\n\n------------------------------------------------\n");
	printf(" Percent |	Source code & Disassembly of %s\n", filename);
	printf("------------------------------------------------\n");

	if (verbose >= 2)
		printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);


	sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename);
	sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (__u64)start, (__u64)end, filename);


@@ -1243,6 +1311,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
	}
	}


	pclose(file);
	pclose(file);
	if (print_line)
		free_source_line(sym, len);
		free_source_line(sym, len);
}
}