Skip to content

Commit

Permalink
perf annotate: Move annotate functions to util/
Browse files Browse the repository at this point in the history
They will be used by perf top, so that we have just one set of routines
to do annotation.

Rename "struct sym_priv" to "struct annotation", etc, to clarify this
code a bit.

Rename "struct sym_ext" to "struct source_line", to give it a meaningful
name, that clarifies that it is a the result of an addr2line call, that
is sorted by percentage one particular source code line appeared in the
annotation.

And since we're moving things around also rename 'sym_hist->ip' to
'sym_hist->addr' as we want to do data structure annotation at some
point.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Arnaldo Carvalho de Melo committed Feb 5, 2011
1 parent 764328d commit 78f7def
Show file tree
Hide file tree
Showing 8 changed files with 578 additions and 503 deletions.
2 changes: 2 additions & 0 deletions tools/perf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ LIB_H += util/include/dwarf-regs.h
LIB_H += util/include/asm/dwarf2.h
LIB_H += util/include/asm/cpufeature.h
LIB_H += perf.h
LIB_H += util/annotate.h
LIB_H += util/cache.h
LIB_H += util/callchain.h
LIB_H += util/build-id.h
Expand Down Expand Up @@ -444,6 +445,7 @@ LIB_H += $(ARCH_INCLUDE)

LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
LIB_OBJS += $(OUTPUT)util/annotate.o
LIB_OBJS += $(OUTPUT)util/build-id.o
LIB_OBJS += $(OUTPUT)util/config.o
LIB_OBJS += $(OUTPUT)util/ctype.o
Expand Down
255 changes: 11 additions & 244 deletions tools/perf/builtin-annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "util/util.h"

#include "util/util.h"
#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
Expand All @@ -18,6 +19,7 @@
#include "perf.h"
#include "util/debug.h"

#include "util/annotate.h"
#include "util/event.h"
#include "util/parse-options.h"
#include "util/parse-events.h"
Expand Down Expand Up @@ -79,245 +81,10 @@ static int process_sample_event(union perf_event *event,
return 0;
}

static int objdump_line__print(struct objdump_line *self,
struct list_head *head,
struct hist_entry *he, u64 len)
{
struct symbol *sym = he->ms.sym;
static const char *prev_line;
static const char *prev_color;

if (self->offset != -1) {
const char *path = NULL;
unsigned int hits = 0;
double percent = 0.0;
const char *color;
struct sym_priv *priv = symbol__priv(sym);
struct sym_ext *sym_ext = priv->ext;
struct sym_hist *h = priv->hist;
s64 offset = self->offset;
struct objdump_line *next = objdump__get_next_ip_line(head, self);

while (offset < (s64)len &&
(next == NULL || offset < next->offset)) {
if (sym_ext) {
if (path == NULL)
path = sym_ext[offset].path;
percent += sym_ext[offset].percent;
} else
hits += h->ip[offset];

++offset;
}

if (sym_ext == NULL && h->sum)
percent = 100.0 * hits / h->sum;

color = get_percent_color(percent);

/*
* Also color the filename and line if needed, with
* the same color than the percentage. Don't print it
* twice for close colored ip with the same filename:line
*/
if (path) {
if (!prev_line || strcmp(prev_line, path)
|| color != prev_color) {
color_fprintf(stdout, color, " %s", path);
prev_line = path;
prev_color = color;
}
}

color_fprintf(stdout, color, " %7.2f", percent);
printf(" : ");
color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
} else {
if (!*self->line)
printf(" :\n");
else
printf(" : %s\n", self->line);
}

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 hist_entry *he, int len)
{
struct sym_priv *priv = symbol__priv(he->ms.sym);
struct sym_ext *sym_ext = priv->ext;
int i;

if (!sym_ext)
return;

for (i = 0; i < len; i++)
free(sym_ext[i].path);
free(sym_ext);

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

/* Get the filename:line for the colored entries */
static void
get_source_line(struct hist_entry *he, int len, const char *filename)
{
struct symbol *sym = he->ms.sym;
u64 start;
int i;
char cmd[PATH_MAX * 2];
struct sym_ext *sym_ext;
struct sym_priv *priv = symbol__priv(sym);
struct sym_hist *h = priv->hist;

if (!h->sum)
return;

sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
if (!priv->ext)
return;

start = he->ms.map->unmap_ip(he->ms.map, sym->start);

for (i = 0; i < len; i++) {
char *path = NULL;
size_t line_len;
u64 offset;
FILE *fp;

sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
if (sym_ext[i].percent <= 0.5)
continue;

offset = start + i;
sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
fp = popen(cmd, "r");
if (!fp)
continue;

if (getline(&path, &line_len, fp) < 0 || !line_len)
goto next;

sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
if (!sym_ext[i].path)
goto next;

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

next:
pclose(fp);
}
}

static void print_summary(const 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;
const char *color;
char *path;

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

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

static void hist_entry__print_hits(struct hist_entry *self)
{
struct symbol *sym = self->ms.sym;
struct sym_priv *priv = symbol__priv(sym);
struct sym_hist *h = priv->hist;
u64 len = sym->end - sym->start, offset;

for (offset = 0; offset < len; ++offset)
if (h->ip[offset] != 0)
printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
sym->start + offset, h->ip[offset]);
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
}

static int hist_entry__tty_annotate(struct hist_entry *he)
{
struct map *map = he->ms.map;
struct dso *dso = map->dso;
struct symbol *sym = he->ms.sym;
const char *filename = dso->long_name, *d_filename;
u64 len;
LIST_HEAD(head);
struct objdump_line *pos, *n;

if (hist_entry__annotate(he, &head, 0) < 0)
return -1;

if (full_paths)
d_filename = filename;
else
d_filename = basename(filename);

len = sym->end - sym->start;

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

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

if (verbose)
hist_entry__print_hits(he);

list_for_each_entry_safe(pos, n, &head, node) {
objdump_line__print(pos, &head, he, len);
list_del(&pos->node);
objdump_line__free(pos);
}

if (print_line)
free_source_line(he, len);

return 0;
return symbol__tty_annotate(he->ms.sym, he->ms.map,
print_line, full_paths);
}

static void hists__find_annotations(struct hists *self)
Expand All @@ -327,13 +94,13 @@ static void hists__find_annotations(struct hists *self)

while (nd) {
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
struct sym_priv *priv;
struct annotation *notes;

if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
goto find_next;

priv = symbol__priv(he->ms.sym);
if (priv->hist == NULL) {
notes = symbol__annotation(he->ms.sym);
if (notes->histogram == NULL) {
find_next:
if (key == KEY_LEFT)
nd = rb_prev(nd);
Expand Down Expand Up @@ -362,11 +129,11 @@ static void hists__find_annotations(struct hists *self)
nd = rb_next(nd);
/*
* Since we have a hist_entry per IP for the same
* symbol, free he->ms.sym->hist to signal we already
* symbol, free he->ms.sym->histogram to signal we already
* processed this symbol.
*/
free(priv->hist);
priv->hist = NULL;
free(notes->histogram);
notes->histogram = NULL;
}
}
}
Expand Down Expand Up @@ -454,7 +221,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)

setup_browser(true);

symbol_conf.priv_size = sizeof(struct sym_priv);
symbol_conf.priv_size = sizeof(struct annotation);
symbol_conf.try_vmlinux_path = true;

if (symbol__init() < 0)
Expand Down
3 changes: 2 additions & 1 deletion tools/perf/builtin-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "util/util.h"

#include "util/annotate.h"
#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
Expand Down Expand Up @@ -508,7 +509,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
* implementation.
*/
if (use_browser > 0) {
symbol_conf.priv_size = sizeof(struct sym_priv);
symbol_conf.priv_size = sizeof(struct annotation);
/*
* For searching by name on the "Browse map details".
* providing it only in verbose mode not to bloat too
Expand Down
Loading

0 comments on commit 78f7def

Please sign in to comment.