Merge branch 'perf/urgent' into perf/core
authorIngo Molnar <mingo@elte.hu>
Tue, 6 Oct 2009 13:02:30 +0000 (15:02 +0200)
committerIngo Molnar <mingo@elte.hu>
Tue, 6 Oct 2009 13:02:34 +0000 (15:02 +0200)
Merge reason: Upcoming patch is dependent on a fix in perf/urgent.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
38 files changed:
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/util/cache.h
tools/perf/util/callchain.h
tools/perf/util/color.h
tools/perf/util/debug.h
tools/perf/util/event.h
tools/perf/util/exec_cmd.h
tools/perf/util/header.h
tools/perf/util/help.h
tools/perf/util/hist.c [new file with mode: 0644]
tools/perf/util/hist.h [new file with mode: 0644]
tools/perf/util/levenshtein.h
tools/perf/util/module.c [deleted file]
tools/perf/util/module.h [deleted file]
tools/perf/util/parse-events.h
tools/perf/util/parse-options.h
tools/perf/util/quote.h
tools/perf/util/run-command.h
tools/perf/util/sigchain.h
tools/perf/util/sort.c [new file with mode: 0644]
tools/perf/util/sort.h [new file with mode: 0644]
tools/perf/util/strbuf.h
tools/perf/util/string.c
tools/perf/util/string.h
tools/perf/util/strlist.h
tools/perf/util/svghelper.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/trace-event.h
tools/perf/util/types.h
tools/perf/util/values.h

index 5881943f0c3430e5023796b0f5e0fc83d40b2796..5a429966c995b86fc868e89c9248f0f5d20d89ed 100644 (file)
@@ -323,6 +323,7 @@ LIB_H += ../../include/linux/rbtree.h
 LIB_H += ../../include/linux/list.h
 LIB_H += util/include/linux/list.h
 LIB_H += perf.h
+LIB_H += util/event.h
 LIB_H += util/types.h
 LIB_H += util/levenshtein.h
 LIB_H += util/parse-options.h
@@ -336,9 +337,11 @@ LIB_H += util/strlist.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
-LIB_H += util/module.h
 LIB_H += util/color.h
 LIB_H += util/values.h
+LIB_H += util/sort.h
+LIB_H += util/hist.h
+LIB_H += util/thread.h
 
 LIB_OBJS += util/abspath.o
 LIB_OBJS += util/alias.o
@@ -361,7 +364,6 @@ LIB_OBJS += util/usage.o
 LIB_OBJS += util/wrapper.o
 LIB_OBJS += util/sigchain.o
 LIB_OBJS += util/symbol.o
-LIB_OBJS += util/module.o
 LIB_OBJS += util/color.o
 LIB_OBJS += util/pager.o
 LIB_OBJS += util/header.o
@@ -374,6 +376,8 @@ LIB_OBJS += util/trace-event-parse.o
 LIB_OBJS += util/trace-event-read.o
 LIB_OBJS += util/trace-event-info.o
 LIB_OBJS += util/svghelper.o
+LIB_OBJS += util/sort.o
+LIB_OBJS += util/hist.o
 
 BUILTIN_OBJS += builtin-annotate.o
 BUILTIN_OBJS += builtin-help.o
index 1ec741615814dddfefb7ad11391e2dfa26ce8b3a..35ed97bd0c6326ea9781f0d14f44979cc56eee47 100644 (file)
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 #include "util/thread.h"
+#include "util/sort.h"
+#include "util/hist.h"
 
 static char            const *input_name = "perf.data";
 
-static char            default_sort_order[] = "comm,symbol";
-static char            *sort_order = default_sort_order;
-
 static int             force;
 static int             input;
-static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
 
 static int             full_paths;
 
@@ -49,248 +47,6 @@ struct sym_ext {
        char            *path;
 };
 
-/*
- * histogram, sorted on item, collects counts
- */
-
-static struct rb_root hist;
-
-struct hist_entry {
-       struct rb_node   rb_node;
-
-       struct thread    *thread;
-       struct map       *map;
-       struct dso       *dso;
-       struct symbol    *sym;
-       u64      ip;
-       char             level;
-
-       uint32_t         count;
-};
-
-/*
- * configurable sorting bits
- */
-
-struct sort_entry {
-       struct list_head list;
-
-       const char *header;
-
-       int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
-       int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
-       size_t  (*print)(FILE *fp, struct hist_entry *);
-};
-
-/* --sort pid */
-
-static int64_t
-sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self)
-{
-       return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
-}
-
-static struct sort_entry sort_thread = {
-       .header = "         Command:  Pid",
-       .cmp    = sort__thread_cmp,
-       .print  = sort__thread_print,
-};
-
-/* --sort comm */
-
-static int64_t
-sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static int64_t
-sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       char *comm_l = left->thread->comm;
-       char *comm_r = right->thread->comm;
-
-       if (!comm_l || !comm_r) {
-               if (!comm_l && !comm_r)
-                       return 0;
-               else if (!comm_l)
-                       return -1;
-               else
-                       return 1;
-       }
-
-       return strcmp(comm_l, comm_r);
-}
-
-static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self)
-{
-       return fprintf(fp, "%16s", self->thread->comm);
-}
-
-static struct sort_entry sort_comm = {
-       .header         = "         Command",
-       .cmp            = sort__comm_cmp,
-       .collapse       = sort__comm_collapse,
-       .print          = sort__comm_print,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct dso *dso_l = left->dso;
-       struct dso *dso_r = right->dso;
-
-       if (!dso_l || !dso_r) {
-               if (!dso_l && !dso_r)
-                       return 0;
-               else if (!dso_l)
-                       return -1;
-               else
-                       return 1;
-       }
-
-       return strcmp(dso_l->name, dso_r->name);
-}
-
-static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self)
-{
-       if (self->dso)
-               return fprintf(fp, "%-25s", self->dso->name);
-
-       return fprintf(fp, "%016llx         ", (u64)self->ip);
-}
-
-static struct sort_entry sort_dso = {
-       .header = "Shared Object            ",
-       .cmp    = sort__dso_cmp,
-       .print  = sort__dso_print,
-};
-
-/* --sort symbol */
-
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       u64 ip_l, ip_r;
-
-       if (left->sym == right->sym)
-               return 0;
-
-       ip_l = left->sym ? left->sym->start : left->ip;
-       ip_r = right->sym ? right->sym->start : right->ip;
-
-       return (int64_t)(ip_r - ip_l);
-}
-
-static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self)
-{
-       size_t ret = 0;
-
-       if (verbose)
-               ret += fprintf(fp, "%#018llx  ", (u64)self->ip);
-
-       if (self->sym) {
-               ret += fprintf(fp, "[%c] %s",
-                       self->dso == kernel_dso ? 'k' : '.', self->sym->name);
-       } else {
-               ret += fprintf(fp, "%#016llx", (u64)self->ip);
-       }
-
-       return ret;
-}
-
-static struct sort_entry sort_sym = {
-       .header = "Symbol",
-       .cmp    = sort__sym_cmp,
-       .print  = sort__sym_print,
-};
-
-static int sort__need_collapse = 0;
-
-struct sort_dimension {
-       const char              *name;
-       struct sort_entry       *entry;
-       int                     taken;
-};
-
-static struct sort_dimension sort_dimensions[] = {
-       { .name = "pid",        .entry = &sort_thread,  },
-       { .name = "comm",       .entry = &sort_comm,    },
-       { .name = "dso",        .entry = &sort_dso,     },
-       { .name = "symbol",     .entry = &sort_sym,     },
-};
-
-static LIST_HEAD(hist_entry__sort_list);
-
-static int sort_dimension__add(char *tok)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
-               struct sort_dimension *sd = &sort_dimensions[i];
-
-               if (sd->taken)
-                       continue;
-
-               if (strncasecmp(tok, sd->name, strlen(tok)))
-                       continue;
-
-               if (sd->entry->collapse)
-                       sort__need_collapse = 1;
-
-               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
-               sd->taken = 1;
-
-               return 0;
-       }
-
-       return -ESRCH;
-}
-
-static int64_t
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               cmp = se->cmp(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
-
-static int64_t
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
-               f = se->collapse ?: se->cmp;
-
-               cmp = f(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
 
 /*
  * collect histogram counts
@@ -306,6 +62,7 @@ static void hist_hit(struct hist_entry *he, u64 ip)
                return;
 
        sym_size = sym->end - sym->start;
+       ip = he->map->map_ip(he->map, ip);
        offset = ip - sym->start;
 
        if (offset >= sym_size)
@@ -322,171 +79,27 @@ static void hist_hit(struct hist_entry *he, u64 ip)
                        sym->hist[offset]);
 }
 
-static int
-hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
-               struct symbol *sym, u64 ip, char level)
+static int hist_entry__add(struct thread *thread, struct map *map,
+                          struct symbol *sym, u64 ip, u64 count, char level)
 {
-       struct rb_node **p = &hist.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *he;
-       struct hist_entry entry = {
-               .thread = thread,
-               .map    = map,
-               .dso    = dso,
-               .sym    = sym,
-               .ip     = ip,
-               .level  = level,
-               .count  = 1,
-       };
-       int cmp;
-
-       while (*p != NULL) {
-               parent = *p;
-               he = rb_entry(parent, struct hist_entry, rb_node);
-
-               cmp = hist_entry__cmp(&entry, he);
-
-               if (!cmp) {
-                       hist_hit(he, ip);
-
-                       return 0;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       he = malloc(sizeof(*he));
-       if (!he)
+       bool hit;
+       struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
+                                                 count, level, &hit);
+       if (he == NULL)
                return -ENOMEM;
-       *he = entry;
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &hist);
-
+       if (hit)
+               hist_hit(he, ip);
        return 0;
 }
 
-static void hist_entry__free(struct hist_entry *he)
-{
-       free(he);
-}
-
-/*
- * collapse the histogram
- */
-
-static struct rb_root collapse_hists;
-
-static void collapse__insert_entry(struct hist_entry *he)
-{
-       struct rb_node **p = &collapse_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-       int64_t cmp;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               cmp = hist_entry__collapse(iter, he);
-
-               if (!cmp) {
-                       iter->count += he->count;
-                       hist_entry__free(he);
-                       return;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &collapse_hists);
-}
-
-static void collapse__resort(void)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-
-       if (!sort__need_collapse)
-               return;
-
-       next = rb_first(&hist);
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, &hist);
-               collapse__insert_entry(n);
-       }
-}
-
-/*
- * reverse the map, sort on count.
- */
-
-static struct rb_root output_hists;
-
-static void output__insert_entry(struct hist_entry *he)
-{
-       struct rb_node **p = &output_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               if (he->count > iter->count)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &output_hists);
-}
-
-static void output__resort(void)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-       struct rb_root *tree = &hist;
-
-       if (sort__need_collapse)
-               tree = &collapse_hists;
-
-       next = rb_first(tree);
-
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, tree);
-               output__insert_entry(n);
-       }
-}
-
-static unsigned long total = 0,
-                    total_mmap = 0,
-                    total_comm = 0,
-                    total_fork = 0,
-                    total_unknown = 0;
-
 static int
 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
-       int show = 0;
-       struct dso *dso = NULL;
        struct thread *thread;
        u64 ip = event->ip.ip;
        struct map *map = NULL;
+       struct symbol *sym = NULL;
 
        thread = threads__findnew(event->ip.pid, &threads, &last_match);
 
@@ -506,51 +119,44 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
        }
 
        if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
                level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
+               sym = kernel_maps__find_symbol(ip, &map);
+               dump_printf(" ...... dso: %s\n",
+                           map ? map->dso->long_name : "<not found>");
        } else if (event->header.misc & PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
                level = '.';
-
                map = thread__find_map(thread, ip);
                if (map != NULL) {
+got_map:
                        ip = map->map_ip(map, ip);
-                       dso = map->dso;
+                       sym = map->dso->find_symbol(map->dso, ip);
                } else {
                        /*
                         * If this is outside of all known maps,
                         * and is a negative address, try to look it
                         * up in the kernel dso, as it might be a
-                        * vsyscall (which executes in user-mode):
+                        * vsyscall or vdso (which executes in user-mode).
+                        *
+                        * XXX This is nasty, we should have a symbol list in
+                        * the "[vdso]" dso, but for now lets use the old
+                        * trick of looking in the whole kernel symbol list.
                         */
-                       if ((long long)ip < 0)
-                               dso = kernel_dso;
+                       if ((long long)ip < 0) {
+                               map = kernel_map;
+                               goto got_map;
+                       }
                }
-               dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
-
+               dump_printf(" ...... dso: %s\n",
+                           map ? map->dso->long_name : "<not found>");
        } else {
-               show = SHOW_HV;
                level = 'H';
                dump_printf(" ...... dso: [hypervisor]\n");
        }
 
-       if (show & show_mask) {
-               struct symbol *sym = NULL;
-
-               if (dso)
-                       sym = dso->find_symbol(dso, ip);
-
-               if (hist_entry__add(thread, map, dso, sym, ip, level)) {
-                       fprintf(stderr,
-               "problem incrementing symbol count, skipping event\n");
-                       return -1;
-               }
+       if (hist_entry__add(thread, map, sym, ip, 1, level)) {
+               fprintf(stderr, "problem incrementing symbol count, "
+                               "skipping event\n");
+               return -1;
        }
        total++;
 
@@ -666,7 +272,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
 }
 
 static int
-parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
+parse_line(FILE *file, struct symbol *sym, u64 len)
 {
        char *line = NULL, *tmp, *tmp2;
        static const char *prev_line;
@@ -716,7 +322,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
                const char *color;
                struct sym_ext *sym_ext = sym->priv;
 
-               offset = line_ip - start;
+               offset = line_ip - sym->start;
                if (offset < len)
                        hits = sym->hist[offset];
 
@@ -795,7 +401,7 @@ static void free_source_line(struct symbol *sym, int len)
 
 /* Get the filename:line for the colored entries */
 static void
-get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
+get_source_line(struct symbol *sym, int len, const char *filename)
 {
        int i;
        char cmd[PATH_MAX * 2];
@@ -820,7 +426,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
                if (sym_ext[i].percent <= 0.5)
                        continue;
 
-               offset = start + i;
+               offset = sym->start + i;
                sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
                fp = popen(cmd, "r");
                if (!fp)
@@ -872,31 +478,23 @@ static void print_summary(const char *filename)
 
 static void annotate_sym(struct dso *dso, struct symbol *sym)
 {
-       const char *filename = dso->name, *d_filename;
-       u64 start, end, len;
+       const char *filename = dso->long_name, *d_filename;
+       u64 len;
        char command[PATH_MAX*2];
        FILE *file;
 
        if (!filename)
                return;
-       if (sym->module)
-               filename = sym->module->path;
-       else if (dso == kernel_dso)
-               filename = vmlinux_name;
-
-       start = sym->obj_start;
-       if (!start)
-               start = sym->start;
+
        if (full_paths)
                d_filename = filename;
        else
                d_filename = basename(filename);
 
-       end = start + sym->end - sym->start + 1;
        len = sym->end - sym->start;
 
        if (print_line) {
-               get_source_line(sym, start, len, filename);
+               get_source_line(sym, len, filename);
                print_summary(filename);
        }
 
@@ -905,10 +503,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
        printf("------------------------------------------------\n");
 
        if (verbose >= 2)
-               printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
+               printf("annotating [%p] %30s : [%p] %30s\n",
+                      dso, dso->long_name, sym, sym->name);
 
        sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
-                       (u64)start, (u64)end, filename, filename);
+               sym->start, sym->end, filename, filename);
 
        if (verbose >= 3)
                printf("doing: %s\n", command);
@@ -918,7 +517,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
                return;
 
        while (!feof(file)) {
-               if (parse_line(file, sym, start, len) < 0)
+               if (parse_line(file, sym, len) < 0)
                        break;
        }
 
@@ -1066,7 +665,7 @@ more:
                dsos__fprintf(stdout);
 
        collapse__resort();
-       output__resort();
+       output__resort(total);
 
        find_annotations();
 
@@ -1139,5 +738,11 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 
        setup_pager();
 
+       if (field_sep && *field_sep == '.') {
+               fputs("'.' is the only non valid --field-separator argument\n",
+                               stderr);
+               exit(129);
+       }
+
        return __cmd_annotate();
 }
index 19669c20088e12a256ebdd736efd0c8253fdd73e..12f8c868fcd7dda57da90918321af4cbb4c70fbd 100644 (file)
 #include "util/parse-events.h"
 
 #include "util/thread.h"
+#include "util/sort.h"
+#include "util/hist.h"
 
 static char            const *input_name = "perf.data";
 
-static char            default_sort_order[] = "comm,dso,symbol";
-static char            *sort_order = default_sort_order;
 static char            *dso_list_str, *comm_list_str, *sym_list_str,
                        *col_width_list_str;
 static struct strlist  *dso_list, *comm_list, *sym_list;
-static char            *field_sep;
 
 static int             force;
 static int             input;
-static int             show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
 
 static int             full_paths;
 static int             show_nr_samples;
@@ -53,16 +51,10 @@ static char         *pretty_printing_style = default_pretty_printing_style;
 static unsigned long   page_size;
 static unsigned long   mmap_window = 32;
 
-static char            default_parent_pattern[] = "^sys_|^do_page_fault";
-static char            *parent_pattern = default_parent_pattern;
-static regex_t         parent_regex;
-
 static int             exclude_other = 1;
 
 static char            callchain_default_opt[] = "fractal,0.5";
 
-static int             callchain;
-
 static char            __cwd[PATH_MAX];
 static char            *cwd = __cwd;
 static int             cwdlen;
@@ -72,346 +64,8 @@ static struct thread        *last_match;
 
 static struct perf_header *header;
 
-static
-struct callchain_param callchain_param = {
-       .mode   = CHAIN_GRAPH_REL,
-       .min_percent = 0.5
-};
-
 static u64             sample_type;
 
-static int repsep_fprintf(FILE *fp, const char *fmt, ...)
-{
-       int n;
-       va_list ap;
-
-       va_start(ap, fmt);
-       if (!field_sep)
-               n = vfprintf(fp, fmt, ap);
-       else {
-               char *bf = NULL;
-               n = vasprintf(&bf, fmt, ap);
-               if (n > 0) {
-                       char *sep = bf;
-
-                       while (1) {
-                               sep = strchr(sep, *field_sep);
-                               if (sep == NULL)
-                                       break;
-                               *sep = '.';
-                       }
-               }
-               fputs(bf, fp);
-               free(bf);
-       }
-       va_end(ap);
-       return n;
-}
-
-static unsigned int dsos__col_width,
-                   comms__col_width,
-                   threads__col_width;
-
-/*
- * histogram, sorted on item, collects counts
- */
-
-static struct rb_root hist;
-
-struct hist_entry {
-       struct rb_node          rb_node;
-
-       struct thread           *thread;
-       struct map              *map;
-       struct dso              *dso;
-       struct symbol           *sym;
-       struct symbol           *parent;
-       u64                     ip;
-       char                    level;
-       struct callchain_node   callchain;
-       struct rb_root          sorted_chain;
-
-       u64                     count;
-};
-
-/*
- * configurable sorting bits
- */
-
-struct sort_entry {
-       struct list_head list;
-
-       const char *header;
-
-       int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
-       int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
-       size_t  (*print)(FILE *fp, struct hist_entry *, unsigned int width);
-       unsigned int *width;
-       bool    elide;
-};
-
-static int64_t cmp_null(void *l, void *r)
-{
-       if (!l && !r)
-               return 0;
-       else if (!l)
-               return -1;
-       else
-               return 1;
-}
-
-/* --sort pid */
-
-static int64_t
-sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static size_t
-sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       return repsep_fprintf(fp, "%*s:%5d", width - 6,
-                             self->thread->comm ?: "", self->thread->pid);
-}
-
-static struct sort_entry sort_thread = {
-       .header = "Command:  Pid",
-       .cmp    = sort__thread_cmp,
-       .print  = sort__thread_print,
-       .width  = &threads__col_width,
-};
-
-/* --sort comm */
-
-static int64_t
-sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       return right->thread->pid - left->thread->pid;
-}
-
-static int64_t
-sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       char *comm_l = left->thread->comm;
-       char *comm_r = right->thread->comm;
-
-       if (!comm_l || !comm_r)
-               return cmp_null(comm_l, comm_r);
-
-       return strcmp(comm_l, comm_r);
-}
-
-static size_t
-sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       return repsep_fprintf(fp, "%*s", width, self->thread->comm);
-}
-
-static struct sort_entry sort_comm = {
-       .header         = "Command",
-       .cmp            = sort__comm_cmp,
-       .collapse       = sort__comm_collapse,
-       .print          = sort__comm_print,
-       .width          = &comms__col_width,
-};
-
-/* --sort dso */
-
-static int64_t
-sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct dso *dso_l = left->dso;
-       struct dso *dso_r = right->dso;
-
-       if (!dso_l || !dso_r)
-               return cmp_null(dso_l, dso_r);
-
-       return strcmp(dso_l->name, dso_r->name);
-}
-
-static size_t
-sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       if (self->dso)
-               return repsep_fprintf(fp, "%-*s", width, self->dso->name);
-
-       return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
-}
-
-static struct sort_entry sort_dso = {
-       .header = "Shared Object",
-       .cmp    = sort__dso_cmp,
-       .print  = sort__dso_print,
-       .width  = &dsos__col_width,
-};
-
-/* --sort symbol */
-
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       u64 ip_l, ip_r;
-
-       if (left->sym == right->sym)
-               return 0;
-
-       ip_l = left->sym ? left->sym->start : left->ip;
-       ip_r = right->sym ? right->sym->start : right->ip;
-
-       return (int64_t)(ip_r - ip_l);
-}
-
-static size_t
-sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
-{
-       size_t ret = 0;
-
-       if (verbose)
-               ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
-                                     dso__symtab_origin(self->dso));
-
-       ret += repsep_fprintf(fp, "[%c] ", self->level);
-       if (self->sym) {
-               ret += repsep_fprintf(fp, "%s", self->sym->name);
-
-               if (self->sym->module)
-                       ret += repsep_fprintf(fp, "\t[%s]",
-                                            self->sym->module->name);
-       } else {
-               ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
-       }
-
-       return ret;
-}
-
-static struct sort_entry sort_sym = {
-       .header = "Symbol",
-       .cmp    = sort__sym_cmp,
-       .print  = sort__sym_print,
-};
-
-/* --sort parent */
-
-static int64_t
-sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct symbol *sym_l = left->parent;
-       struct symbol *sym_r = right->parent;
-
-       if (!sym_l || !sym_r)
-               return cmp_null(sym_l, sym_r);
-
-       return strcmp(sym_l->name, sym_r->name);
-}
-
-static size_t
-sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
-{
-       return repsep_fprintf(fp, "%-*s", width,
-                             self->parent ? self->parent->name : "[other]");
-}
-
-static unsigned int parent_symbol__col_width;
-
-static struct sort_entry sort_parent = {
-       .header = "Parent symbol",
-       .cmp    = sort__parent_cmp,
-       .print  = sort__parent_print,
-       .width  = &parent_symbol__col_width,
-};
-
-static int sort__need_collapse = 0;
-static int sort__has_parent = 0;
-
-struct sort_dimension {
-       const char              *name;
-       struct sort_entry       *entry;
-       int                     taken;
-};
-
-static struct sort_dimension sort_dimensions[] = {
-       { .name = "pid",        .entry = &sort_thread,  },
-       { .name = "comm",       .entry = &sort_comm,    },
-       { .name = "dso",        .entry = &sort_dso,     },
-       { .name = "symbol",     .entry = &sort_sym,     },
-       { .name = "parent",     .entry = &sort_parent,  },
-};
-
-static LIST_HEAD(hist_entry__sort_list);
-
-static int sort_dimension__add(const char *tok)
-{
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
-               struct sort_dimension *sd = &sort_dimensions[i];
-
-               if (sd->taken)
-                       continue;
-
-               if (strncasecmp(tok, sd->name, strlen(tok)))
-                       continue;
-
-               if (sd->entry->collapse)
-                       sort__need_collapse = 1;
-
-               if (sd->entry == &sort_parent) {
-                       int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
-                       if (ret) {
-                               char err[BUFSIZ];
-
-                               regerror(ret, &parent_regex, err, sizeof(err));
-                               fprintf(stderr, "Invalid regex: %s\n%s",
-                                       parent_pattern, err);
-                               exit(-1);
-                       }
-                       sort__has_parent = 1;
-               }
-
-               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
-               sd->taken = 1;
-
-               return 0;
-       }
-
-       return -ESRCH;
-}
-
-static int64_t
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               cmp = se->cmp(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
-
-static int64_t
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
-{
-       struct sort_entry *se;
-       int64_t cmp = 0;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               int64_t (*f)(struct hist_entry *, struct hist_entry *);
-
-               f = se->collapse ?: se->cmp;
-
-               cmp = f(left, right);
-               if (cmp)
-                       break;
-       }
-
-       return cmp;
-}
-
 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
 {
        int i;
@@ -610,7 +264,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
        return ret;
 }
 
-
 static size_t
 hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 {
@@ -695,22 +348,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
 
 
 static struct symbol *
-resolve_symbol(struct thread *thread, struct map **mapp,
-              struct dso **dsop, u64 *ipp)
+resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
 {
-       struct dso *dso = dsop ? *dsop : NULL;
        struct map *map = mapp ? *mapp : NULL;
        u64 ip = *ipp;
 
-       if (!thread)
-               return NULL;
-
-       if (dso)
-               goto got_dso;
-
        if (map)
                goto got_map;
 
+       if (!thread)
+               return NULL;
+
        map = thread__find_map(thread, ip);
        if (map != NULL) {
                /*
@@ -725,29 +373,26 @@ resolve_symbol(struct thread *thread, struct map **mapp,
                        *mapp = map;
 got_map:
                ip = map->map_ip(map, ip);
-
-               dso = map->dso;
        } else {
                /*
                 * If this is outside of all known maps,
                 * and is a negative address, try to look it
                 * up in the kernel dso, as it might be a
-                * vsyscall (which executes in user-mode):
+                * vsyscall or vdso (which executes in user-mode).
+                *
+                * XXX This is nasty, we should have a symbol list in
+                * the "[vdso]" dso, but for now lets use the old
+                * trick of looking in the whole kernel symbol list.
                 */
                if ((long long)ip < 0)
-               dso = kernel_dso;
+                       return kernel_maps__find_symbol(ip, mapp);
        }
-       dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
+       dump_printf(" ...... dso: %s\n",
+                   map ? map->dso->long_name : "<not found>");
        dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
        *ipp  = ip;
 
-       if (dsop)
-               *dsop = dso;
-
-       if (!dso)
-               return NULL;
-got_dso:
-       return dso->find_symbol(dso, ip);
+       return map ? map->dso->find_symbol(map->dso, ip) : NULL;
 }
 
 static int call__match(struct symbol *sym)
@@ -758,9 +403,9 @@ static int call__match(struct symbol *sym)
        return 0;
 }
 
-static struct symbol **
-resolve_callchain(struct thread *thread, struct map *map __used,
-                   struct ip_callchain *chain, struct hist_entry *entry)
+static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
+                                        struct ip_callchain *chain,
+                                        struct symbol **parent)
 {
        u64 context = PERF_CONTEXT_MAX;
        struct symbol **syms = NULL;
@@ -776,8 +421,7 @@ resolve_callchain(struct thread *thread, struct map *map __used,
 
        for (i = 0; i < chain->nr; i++) {
                u64 ip = chain->ips[i];
-               struct dso *dso = NULL;
-               struct symbol *sym;
+               struct symbol *sym = NULL;
 
                if (ip >= PERF_CONTEXT_MAX) {
                        context = ip;
@@ -786,21 +430,18 @@ resolve_callchain(struct thread *thread, struct map *map __used,
 
                switch (context) {
                case PERF_CONTEXT_HV:
-                       dso = hypervisor_dso;
                        break;
                case PERF_CONTEXT_KERNEL:
-                       dso = kernel_dso;
+                       sym = kernel_maps__find_symbol(ip, &map);
                        break;
                default:
+                       sym = resolve_symbol(thread, &map, &ip);
                        break;
                }
 
-               sym = resolve_symbol(thread, NULL, &dso, &ip);
-
                if (sym) {
-                       if (sort__has_parent && call__match(sym) &&
-                           !entry->parent)
-                               entry->parent = sym;
+                       if (sort__has_parent && !*parent && call__match(sym))
+                               *parent = sym;
                        if (!callchain)
                                break;
                        syms[i] = sym;
@@ -815,177 +456,35 @@ resolve_callchain(struct thread *thread, struct map *map __used,
  */
 
 static int
-hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
+hist_entry__add(struct thread *thread, struct map *map,
                struct symbol *sym, u64 ip, struct ip_callchain *chain,
                char level, u64 count)
 {
-       struct rb_node **p = &hist.rb_node;
-       struct rb_node *parent = NULL;
+       struct symbol **syms = NULL, *parent = NULL;
+       bool hit;
        struct hist_entry *he;
-       struct symbol **syms = NULL;
-       struct hist_entry entry = {
-               .thread = thread,
-               .map    = map,
-               .dso    = dso,
-               .sym    = sym,
-               .ip     = ip,
-               .level  = level,
-               .count  = count,
-               .parent = NULL,
-               .sorted_chain = RB_ROOT
-       };
-       int cmp;
 
        if ((sort__has_parent || callchain) && chain)
-               syms = resolve_callchain(thread, map, chain, &entry);
-
-       while (*p != NULL) {
-               parent = *p;
-               he = rb_entry(parent, struct hist_entry, rb_node);
+               syms = resolve_callchain(thread, map, chain, &parent);
 
-               cmp = hist_entry__cmp(&entry, he);
+       he = __hist_entry__add(thread, map, sym, parent,
+                              ip, count, level, &hit);
+       if (he == NULL)
+               return -ENOMEM;
 
-               if (!cmp) {
-                       he->count += count;
-                       if (callchain) {
-                               append_chain(&he->callchain, chain, syms);
-                               free(syms);
-                       }
-                       return 0;
-               }
+       if (hit)
+               he->count += count;
 
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       he = malloc(sizeof(*he));
-       if (!he)
-               return -ENOMEM;
-       *he = entry;
        if (callchain) {
-               callchain_init(&he->callchain);
+               if (!hit)
+                       callchain_init(&he->callchain);
                append_chain(&he->callchain, chain, syms);
                free(syms);
        }
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &hist);
 
        return 0;
 }
 
-static void hist_entry__free(struct hist_entry *he)
-{
-       free(he);
-}
-
-/*
- * collapse the histogram
- */
-
-static struct rb_root collapse_hists;
-
-static void collapse__insert_entry(struct hist_entry *he)
-{
-       struct rb_node **p = &collapse_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-       int64_t cmp;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               cmp = hist_entry__collapse(iter, he);
-
-               if (!cmp) {
-                       iter->count += he->count;
-                       hist_entry__free(he);
-                       return;
-               }
-
-               if (cmp < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &collapse_hists);
-}
-
-static void collapse__resort(void)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-
-       if (!sort__need_collapse)
-               return;
-
-       next = rb_first(&hist);
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, &hist);
-               collapse__insert_entry(n);
-       }
-}
-
-/*
- * reverse the map, sort on count.
- */
-
-static struct rb_root output_hists;
-
-static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
-{
-       struct rb_node **p = &output_hists.rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-
-       if (callchain)
-               callchain_param.sort(&he->sorted_chain, &he->callchain,
-                                     min_callchain_hits, &callchain_param);
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-
-               if (he->count > iter->count)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, &output_hists);
-}
-
-static void output__resort(u64 total_samples)
-{
-       struct rb_node *next;
-       struct hist_entry *n;
-       struct rb_root *tree = &hist;
-       u64 min_callchain_hits;
-
-       min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
-
-       if (sort__need_collapse)
-               tree = &collapse_hists;
-
-       next = rb_first(tree);
-
-       while (next) {
-               n = rb_entry(next, struct hist_entry, rb_node);
-               next = rb_next(&n->rb_node);
-
-               rb_erase(&n->rb_node, tree);
-               output__insert_entry(n, min_callchain_hits);
-       }
-}
-
 static size_t output__fprintf(FILE *fp, u64 total_samples)
 {
        struct hist_entry *pos;
@@ -1080,13 +579,6 @@ print_entries:
        return ret;
 }
 
-static unsigned long total = 0,
-                    total_mmap = 0,
-                    total_comm = 0,
-                    total_fork = 0,
-                    total_unknown = 0,
-                    total_lost = 0;
-
 static int validate_chain(struct ip_callchain *chain, event_t *event)
 {
        unsigned int chain_size;
@@ -1104,8 +596,7 @@ static int
 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
-       int show = 0;
-       struct dso *dso = NULL;
+       struct symbol *sym = NULL;
        struct thread *thread;
        u64 ip = event->ip.ip;
        u64 period = 1;
@@ -1161,42 +652,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
        cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
        if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
                level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
+               sym = kernel_maps__find_symbol(ip, &map);
+               dump_printf(" ...... dso: %s\n",
+                           map ? map->dso->long_name : "<not found>");
        } else if (cpumode == PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
                level = '.';
+               sym = resolve_symbol(thread, &map, &ip);
 
        } else {
-               show = SHOW_HV;
                level = 'H';
-
-               dso = hypervisor_dso;
-
                dump_printf(" ...... dso: [hypervisor]\n");
        }
 
-       if (show & show_mask) {
-               struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
-
-               if (dso_list && (!dso || !dso->name ||
-                                !strlist__has_entry(dso_list, dso->name)))
-                       return 0;
+       if (dso_list &&
+           (!map || !map->dso ||
+            !(strlist__has_entry(dso_list, map->dso->short_name) ||
+              (map->dso->short_name != map->dso->long_name &&
+               strlist__has_entry(dso_list, map->dso->long_name)))))
+               return 0;
 
-               if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
-                       return 0;
+       if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+               return 0;
 
-               if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
-                       eprintf("problem incrementing symbol count, skipping event\n");
-                       return -1;
-               }
+       if (hist_entry__add(thread, map, sym, ip,
+                           chain, level, period)) {
+               eprintf("problem incrementing symbol count, skipping event\n");
+               return -1;
        }
+
        total += period;
 
        return 0;
@@ -1606,7 +1090,8 @@ setup:
        return 0;
 }
 
-static const char * const report_usage[] = {
+//static const char * const report_usage[] = {
+const char * const report_usage[] = {
        "perf report [<options>] <command>",
        NULL
 };
index ea9c15c0cdfe0d96fa7c489956e2beb39df77bbe..4470f2535706e76909e09031647406ac3f19f0ac 100644 (file)
@@ -1544,16 +1544,15 @@ process_raw_event(event_t *raw_event __used, void *more_data,
 static int
 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       char level;
-       int show = 0;
-       struct dso *dso = NULL;
        struct thread *thread;
        u64 ip = event->ip.ip;
        u64 timestamp = -1;
        u32 cpu = -1;
        u64 period = 1;
        void *more_data = event->ip.__more_data;
-       int cpumode;
+
+       if (!(sample_type & PERF_SAMPLE_RAW))
+               return 0;
 
        thread = threads__findnew(event->ip.pid, &threads, &last_match);
 
@@ -1589,32 +1588,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                return -1;
        }
 
-       cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
-       if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
-               level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
-       } else if (cpumode == PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
-               level = '.';
-
-       } else {
-               show = SHOW_HV;
-               level = 'H';
-
-               dso = hypervisor_dso;
-
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
-
-       if (sample_type & PERF_SAMPLE_RAW)
-               process_raw_event(event, more_data, cpu, timestamp, thread);
+       process_raw_event(event, more_data, cpu, timestamp, thread);
 
        return 0;
 }
index 37512e936235359aa4ebbf93d21831cce56750d7..c574c5b3d0e6e78759e03876d6ae686d39f62f1b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "util/symbol.h"
 #include "util/color.h"
+#include "util/thread.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
 #include "util/parse-options.h"
@@ -96,9 +97,6 @@ static int                    display_weighted                = -1;
  * Symbols
  */
 
-static u64                     min_ip;
-static u64                     max_ip = -1ll;
-
 struct sym_entry {
        struct rb_node          rb_node;
        struct list_head        node;
@@ -106,6 +104,7 @@ struct sym_entry {
        unsigned long           snap_count;
        double                  weight;
        int                     skip;
+       struct map              *map;
        struct source_line      *source;
        struct source_line      *lines;
        struct source_line      **lines_tail;
@@ -119,12 +118,11 @@ struct sym_entry {
 static void parse_source(struct sym_entry *syme)
 {
        struct symbol *sym;
-       struct module *module;
-       struct section *section = NULL;
+       struct map *map;
        FILE *file;
        char command[PATH_MAX*2];
-       const char *path = vmlinux_name;
-       u64 start, end, len;
+       const char *path;
+       u64 len;
 
        if (!syme)
                return;
@@ -135,27 +133,15 @@ static void parse_source(struct sym_entry *syme)
        }
 
        sym = (struct symbol *)(syme + 1);
-       module = sym->module;
-
-       if (module)
-               path = module->path;
-       if (!path)
-               return;
-
-       start = sym->obj_start;
-       if (!start)
-               start = sym->start;
+       map = syme->map;
+       path = map->dso->long_name;
 
-       if (module) {
-               section = module->sections->find_section(module->sections, ".text");
-               if (section)
-                       start -= section->vma;
-       }
-
-       end = start + sym->end - sym->start + 1;
        len = sym->end - sym->start;
 
-       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
+       sprintf(command,
+               "objdump --start-address=0x%016Lx "
+                        "--stop-address=0x%016Lx -dS %s",
+               sym->start, sym->end, path);
 
        file = popen(command, "r");
        if (!file)
@@ -187,13 +173,11 @@ static void parse_source(struct sym_entry *syme)
 
                if (strlen(src->line)>8 && src->line[8] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
-                       if (section)
-                               src->eip += section->vma;
+                       src->eip += map->start;
                }
                if (strlen(src->line)>8 && src->line[16] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
-                       if (section)
-                               src->eip += section->vma;
+                       src->eip += map->start;
                }
        }
        pclose(file);
@@ -245,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme)
        struct symbol *symbol = (struct symbol *)(syme + 1);
        struct source_line *line;
        char pattern[PATH_MAX];
-       char *idx;
 
        sprintf(pattern, "<%s>:", symbol->name);
 
-       if (symbol->module) {
-               idx = strstr(pattern, "\t");
-               if (idx)
-                       *idx = 0;
-       }
-
        pthread_mutex_lock(&syme->source_lock);
        for (line = syme->lines; line; line = line->next) {
                if (strstr(line->line, pattern)) {
@@ -516,8 +493,8 @@ static void print_sym_table(void)
                if (verbose)
                        printf(" - %016llx", sym->start);
                printf(" : %s", sym->name);
-               if (sym->module)
-                       printf("\t[%s]", sym->module->name);
+               if (syme->map->dso->name[0] == '[')
+                       printf(" \t%s", syme->map->dso->name);
                printf("\n");
        }
 }
@@ -788,7 +765,7 @@ static const char *skip_symbols[] = {
        NULL
 };
 
-static int symbol_filter(struct dso *self, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
 {
        struct sym_entry *syme;
        const char *name = sym->name;
@@ -810,7 +787,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
            strstr(name, "_text_end"))
                return 1;
 
-       syme = dso__sym_priv(self, sym);
+       syme = dso__sym_priv(map->dso, sym);
+       syme->map = map;
        pthread_mutex_init(&syme->source_lock, NULL);
        if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
                sym_filter_entry = syme;
@@ -827,34 +805,14 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
 
 static int parse_symbols(void)
 {
-       struct rb_node *node;
-       struct symbol  *sym;
-       int use_modules = vmlinux_name ? 1 : 0;
-
-       kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
-       if (kernel_dso == NULL)
+       if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
+                             symbol_filter, verbose, 1) <= 0)
                return -1;
 
-       if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
-               goto out_delete_dso;
-
-       node = rb_first(&kernel_dso->syms);
-       sym = rb_entry(node, struct symbol, rb_node);
-       min_ip = sym->start;
-
-       node = rb_last(&kernel_dso->syms);
-       sym = rb_entry(node, struct symbol, rb_node);
-       max_ip = sym->end;
-
        if (dump_symtab)
-               dso__fprintf(kernel_dso, stderr);
+               dsos__fprintf(stderr);
 
        return 0;
-
-out_delete_dso:
-       dso__delete(kernel_dso);
-       kernel_dso = NULL;
-       return -1;
 }
 
 /*
@@ -862,10 +820,11 @@ out_delete_dso:
  */
 static void record_ip(u64 ip, int counter)
 {
-       struct symbol *sym = dso__find_symbol(kernel_dso, ip);
+       struct map *map;
+       struct symbol *sym = kernel_maps__find_symbol(ip, &map);
 
        if (sym != NULL) {
-               struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
+               struct sym_entry *syme = dso__sym_priv(map->dso, sym);
 
                if (!syme->skip) {
                        syme->count[counter]++;
index 0c5e4f72f2bae827ee0456f7362aff1f0ad20a91..5d4c84d86373753718b1590636969c9acf9d2abf 100644 (file)
@@ -53,16 +53,12 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
 static int
 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       char level;
-       int show = 0;
-       struct dso *dso = NULL;
        struct thread *thread;
        u64 ip = event->ip.ip;
        u64 timestamp = -1;
        u32 cpu = -1;
        u64 period = 1;
        void *more_data = event->ip.__more_data;
-       int cpumode;
 
        thread = threads__findnew(event->ip.pid, &threads, &last_match);
 
@@ -98,30 +94,6 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                return -1;
        }
 
-       cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
-       if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               show = SHOW_KERNEL;
-               level = 'k';
-
-               dso = kernel_dso;
-
-               dump_printf(" ...... dso: %s\n", dso->name);
-
-       } else if (cpumode == PERF_RECORD_MISC_USER) {
-
-               show = SHOW_USER;
-               level = '.';
-
-       } else {
-               show = SHOW_HV;
-               level = 'H';
-
-               dso = hypervisor_dso;
-
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
-
        if (sample_type & PERF_SAMPLE_RAW) {
                struct {
                        u32 size;
index 6f8ea9d210b6d822f2e2ee57e99a3a520f516b73..f26172c0c9191a4ea574a013a70fcd2a32a2fea2 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef CACHE_H
-#define CACHE_H
+#ifndef __PERF_CACHE_H
+#define __PERF_CACHE_H
 
 #include "util.h"
 #include "strbuf.h"
@@ -117,4 +117,4 @@ extern char *perf_pathdup(const char *fmt, ...)
 
 extern size_t strlcpy(char *dest, const char *src, size_t size);
 
-#endif /* CACHE_H */
+#endif /* __PERF_CACHE_H */
index 43cf3ea9e088fd86953637450036ecb56f3964fd..ad4626de4c2b9cfa8deb5c5b49b42c644a95a761 100644 (file)
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
 int register_callchain_param(struct callchain_param *param);
 void append_chain(struct callchain_node *root, struct ip_callchain *chain,
                  struct symbol **syms);
-#endif
+#endif /* __PERF_CALLCHAIN_H */
index 58d597564b9960f7d43923248c27c7c450917816..24e8809210bbbc8af8e46c8f137b6e1032d199d7 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef COLOR_H
-#define COLOR_H
+#ifndef __PERF_COLOR_H
+#define __PERF_COLOR_H
 
 /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
 #define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
 int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
 const char *get_percent_color(double percent);
 
-#endif /* COLOR_H */
+#endif /* __PERF_COLOR_H */
index 437eea58ce406058bd5037ad7450e6e99de7f302..02d1fa1c2465230f5286dfa3592ef5ae17d4721b 100644 (file)
@@ -1,4 +1,6 @@
 /* For debugging general purposes */
+#ifndef __PERF_DEBUG_H
+#define __PERF_DEBUG_H
 
 extern int verbose;
 extern int dump_trace;
@@ -6,3 +8,5 @@ extern int dump_trace;
 int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(event_t *event);
+
+#endif /* __PERF_DEBUG_H */
index 2c9c26d6ded0aff8f3679c01b0cb93a386194738..c2e62be62798a62d1cc81341a9de872621c29ee1 100644 (file)
@@ -1,14 +1,10 @@
 #ifndef __PERF_RECORD_H
 #define __PERF_RECORD_H
+
 #include "../perf.h"
 #include "util.h"
 #include <linux/list.h>
-
-enum {
-       SHOW_KERNEL     = 1,
-       SHOW_USER       = 2,
-       SHOW_HV         = 4,
-};
+#include <linux/rbtree.h>
 
 /*
  * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -78,7 +74,10 @@ typedef union event_union {
 } event_t;
 
 struct map {
-       struct list_head        node;
+       union {
+               struct rb_node  rb_node;
+               struct list_head node;
+       };
        u64                     start;
        u64                     end;
        u64                     pgoff;
@@ -101,4 +100,4 @@ struct map *map__clone(struct map *self);
 int map__overlap(struct map *l, struct map *r);
 size_t map__fprintf(struct map *self, FILE *fp);
 
-#endif
+#endif /* __PERF_RECORD_H */
index effe25eb15456dcad9bc6233eb19f38193af2623..31647ac92ed1733e71dade59609c310563193b31 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef PERF_EXEC_CMD_H
-#define PERF_EXEC_CMD_H
+#ifndef __PERF_EXEC_CMD_H
+#define __PERF_EXEC_CMD_H
 
 extern void perf_set_argv_exec_path(const char *exec_path);
 extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
 extern int execl_perf_cmd(const char *cmd, ...);
 extern const char *system_path(const char *path);
 
-#endif /* PERF_EXEC_CMD_H */
+#endif /* __PERF_EXEC_CMD_H */
index a0761bc7863c7e2ba7ad644751fa668c092a67a6..a2916b652a1b5960caad669bbc2d177c12210e0d 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PERF_HEADER_H
-#define _PERF_HEADER_H
+#ifndef __PERF_HEADER_H
+#define __PERF_HEADER_H
 
 #include "../../../include/linux/perf_event.h"
 #include <sys/types.h>
@@ -44,4 +44,4 @@ perf_header__find_attr(u64 id, struct perf_header *header);
 
 struct perf_header *perf_header__new(void);
 
-#endif /* _PERF_HEADER_H */
+#endif /* __PERF_HEADER_H */
index 7128783637b4a7be720c49a9e74ccb43cba2cac9..7f5c6dedd714ff8492cce6998c866becfd7bf8d3 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef HELP_H
-#define HELP_H
+#ifndef __PERF_HELP_H
+#define __PERF_HELP_H
 
 struct cmdnames {
        size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
 void list_commands(const char *title, struct cmdnames *main_cmds,
                   struct cmdnames *other_cmds);
 
-#endif /* HELP_H */
+#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644 (file)
index 0000000..7393a02
--- /dev/null
@@ -0,0 +1,210 @@
+#include "hist.h"
+
+struct rb_root hist;
+struct rb_root collapse_hists;
+struct rb_root output_hists;
+int callchain;
+
+struct callchain_param callchain_param = {
+       .mode   = CHAIN_GRAPH_REL,
+       .min_percent = 0.5
+};
+
+unsigned long total;
+unsigned long total_mmap;
+unsigned long total_comm;
+unsigned long total_fork;
+unsigned long total_unknown;
+unsigned long total_lost;
+
+/*
+ * histogram, sorted on item, collects counts
+ */
+
+struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
+                                    struct symbol *sym,
+                                    struct symbol *sym_parent,
+                                    u64 ip, u64 count, char level, bool *hit)
+{
+       struct rb_node **p = &hist.rb_node;
+       struct rb_node *parent = NULL;
+       struct hist_entry *he;
+       struct hist_entry entry = {
+               .thread = thread,
+               .map    = map,
+               .sym    = sym,
+               .ip     = ip,
+               .level  = level,
+               .count  = count,
+               .parent = sym_parent,
+       };
+       int cmp;
+
+       while (*p != NULL) {
+               parent = *p;
+               he = rb_entry(parent, struct hist_entry, rb_node);
+
+               cmp = hist_entry__cmp(&entry, he);
+
+               if (!cmp) {
+                       *hit = true;
+                       return he;
+               }
+
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       he = malloc(sizeof(*he));
+       if (!he)
+               return NULL;
+       *he = entry;
+       rb_link_node(&he->rb_node, parent, p);
+       rb_insert_color(&he->rb_node, &hist);
+       *hit = false;
+       return he;
+}
+
+int64_t
+hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct sort_entry *se;
+       int64_t cmp = 0;
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               cmp = se->cmp(left, right);
+               if (cmp)
+                       break;
+       }
+
+       return cmp;
+}
+
+int64_t
+hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
+{
+       struct sort_entry *se;
+       int64_t cmp = 0;
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               int64_t (*f)(struct hist_entry *, struct hist_entry *);
+
+               f = se->collapse ?: se->cmp;
+
+               cmp = f(left, right);
+               if (cmp)
+                       break;
+       }
+
+       return cmp;
+}
+
+void hist_entry__free(struct hist_entry *he)
+{
+       free(he);
+}
+
+/*
+ * collapse the histogram
+ */
+
+void collapse__insert_entry(struct hist_entry *he)
+{
+       struct rb_node **p = &collapse_hists.rb_node;
+       struct rb_node *parent = NULL;
+       struct hist_entry *iter;
+       int64_t cmp;
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct hist_entry, rb_node);
+
+               cmp = hist_entry__collapse(iter, he);
+
+               if (!cmp) {
+                       iter->count += he->count;
+                       hist_entry__free(he);
+                       return;
+               }
+
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&he->rb_node, parent, p);
+       rb_insert_color(&he->rb_node, &collapse_hists);
+}
+
+void collapse__resort(void)
+{
+       struct rb_node *next;
+       struct hist_entry *n;
+
+       if (!sort__need_collapse)
+               return;
+
+       next = rb_first(&hist);
+       while (next) {
+               n = rb_entry(next, struct hist_entry, rb_node);
+               next = rb_next(&n->rb_node);
+
+               rb_erase(&n->rb_node, &hist);
+               collapse__insert_entry(n);
+       }
+}
+
+/*
+ * reverse the map, sort on count.
+ */
+
+void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
+{
+       struct rb_node **p = &output_hists.rb_node;
+       struct rb_node *parent = NULL;
+       struct hist_entry *iter;
+
+       if (callchain)
+               callchain_param.sort(&he->sorted_chain, &he->callchain,
+                                     min_callchain_hits, &callchain_param);
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct hist_entry, rb_node);
+
+               if (he->count > iter->count)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&he->rb_node, parent, p);
+       rb_insert_color(&he->rb_node, &output_hists);
+}
+
+void output__resort(u64 total_samples)
+{
+       struct rb_node *next;
+       struct hist_entry *n;
+       struct rb_root *tree = &hist;
+       u64 min_callchain_hits;
+
+       min_callchain_hits =
+               total_samples * (callchain_param.min_percent / 100);
+
+       if (sort__need_collapse)
+               tree = &collapse_hists;
+
+       next = rb_first(tree);
+
+       while (next) {
+               n = rb_entry(next, struct hist_entry, rb_node);
+               next = rb_next(&n->rb_node);
+
+               rb_erase(&n->rb_node, tree);
+               output__insert_entry(n, min_callchain_hits);
+       }
+}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644 (file)
index 0000000..ac2149c
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __PERF_HIST_H
+#define __PERF_HIST_H
+#include "../builtin.h"
+
+#include "util.h"
+
+#include "color.h"
+#include <linux/list.h>
+#include "cache.h"
+#include <linux/rbtree.h>
+#include "symbol.h"
+#include "string.h"
+#include "callchain.h"
+#include "strlist.h"
+#include "values.h"
+
+#include "../perf.h"
+#include "debug.h"
+#include "header.h"
+
+#include "parse-options.h"
+#include "parse-events.h"
+
+#include "thread.h"
+#include "sort.h"
+
+extern struct rb_root hist;
+extern struct rb_root collapse_hists;
+extern struct rb_root output_hists;
+extern int callchain;
+extern struct callchain_param callchain_param;
+extern unsigned long total;
+extern unsigned long total_mmap;
+extern unsigned long total_comm;
+extern unsigned long total_fork;
+extern unsigned long total_unknown;
+extern unsigned long total_lost;
+
+struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
+                                    struct symbol *sym, struct symbol *parent,
+                                    u64 ip, u64 count, char level, bool *hit);
+extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
+extern void hist_entry__free(struct hist_entry *);
+extern void collapse__insert_entry(struct hist_entry *);
+extern void collapse__resort(void);
+extern void output__insert_entry(struct hist_entry *, u64);
+extern void output__resort(u64);
+
+#endif /* __PERF_HIST_H */
index 0173abeef52c8dc3930a5c36420ff073ba8ddc87..b0fcb6d8a881d88b021cfcd7e1a08805b006ed3d 100644 (file)
@@ -1,8 +1,8 @@
-#ifndef LEVENSHTEIN_H
-#define LEVENSHTEIN_H
+#ifndef __PERF_LEVENSHTEIN_H
+#define __PERF_LEVENSHTEIN_H
 
 int levenshtein(const char *string1, const char *string2,
        int swap_penalty, int substition_penalty,
        int insertion_penalty, int deletion_penalty);
 
-#endif
+#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644 (file)
index 0d8c85d..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-#include "util.h"
-#include "../perf.h"
-#include "string.h"
-#include "module.h"
-
-#include <libelf.h>
-#include <libgen.h>
-#include <gelf.h>
-#include <elf.h>
-#include <dirent.h>
-#include <sys/utsname.h>
-
-static unsigned int crc32(const char *p, unsigned int len)
-{
-       int i;
-       unsigned int crc = 0;
-
-       while (len--) {
-               crc ^= *p++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
-       }
-       return crc;
-}
-
-/* module section methods */
-
-struct sec_dso *sec_dso__new_dso(const char *name)
-{
-       struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
-
-       if (self != NULL) {
-               strcpy(self->name, name);
-               self->secs = RB_ROOT;
-               self->find_section = sec_dso__find_section;
-       }
-
-       return self;
-}
-
-static void sec_dso__delete_section(struct section *self)
-{
-       free(((void *)self));
-}
-
-void sec_dso__delete_sections(struct sec_dso *self)
-{
-       struct section *pos;
-       struct rb_node *next = rb_first(&self->secs);
-
-       while (next) {
-               pos = rb_entry(next, struct section, rb_node);
-               next = rb_next(&pos->rb_node);
-               rb_erase(&pos->rb_node, &self->secs);
-               sec_dso__delete_section(pos);
-       }
-}
-
-void sec_dso__delete_self(struct sec_dso *self)
-{
-       sec_dso__delete_sections(self);
-       free(self);
-}
-
-static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
-{
-       struct rb_node **p = &self->secs.rb_node;
-       struct rb_node *parent = NULL;
-       const u64 hash = sec->hash;
-       struct section *s;
-
-       while (*p != NULL) {
-               parent = *p;
-               s = rb_entry(parent, struct section, rb_node);
-               if (hash < s->hash)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-       rb_link_node(&sec->rb_node, parent, p);
-       rb_insert_color(&sec->rb_node, &self->secs);
-}
-
-struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
-{
-       struct rb_node *n;
-       u64 hash;
-       int len;
-
-       if (self == NULL)
-               return NULL;
-
-       len = strlen(name);
-       hash = crc32(name, len);
-
-       n = self->secs.rb_node;
-
-       while (n) {
-               struct section *s = rb_entry(n, struct section, rb_node);
-
-               if (hash < s->hash)
-                       n = n->rb_left;
-               else if (hash > s->hash)
-                       n = n->rb_right;
-               else {
-                       if (!strcmp(name, s->name))
-                               return s;
-                       else
-                               n = rb_next(&s->rb_node);
-               }
-       }
-
-       return NULL;
-}
-
-static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
-{
-       return fprintf(fp, "name:%s vma:%llx path:%s\n",
-                      self->name, self->vma, self->path);
-}
-
-size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
-{
-       size_t ret = fprintf(fp, "dso: %s\n", self->name);
-
-       struct rb_node *nd;
-       for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
-               struct section *pos = rb_entry(nd, struct section, rb_node);
-               ret += sec_dso__fprintf_section(pos, fp);
-       }
-
-       return ret;
-}
-
-static struct section *section__new(const char *name, const char *path)
-{
-       struct section *self = calloc(1, sizeof(*self));
-
-       if (!self)
-               goto out_failure;
-
-       self->name = calloc(1, strlen(name) + 1);
-       if (!self->name)
-               goto out_failure;
-
-       self->path = calloc(1, strlen(path) + 1);
-       if (!self->path)
-               goto out_failure;
-
-       strcpy(self->name, name);
-       strcpy(self->path, path);
-       self->hash = crc32(self->name, strlen(name));
-
-       return self;
-
-out_failure:
-       if (self) {
-               if (self->name)
-                       free(self->name);
-               if (self->path)
-                       free(self->path);
-               free(self);
-       }
-
-       return NULL;
-}
-
-/* module methods */
-
-struct mod_dso *mod_dso__new_dso(const char *name)
-{
-       struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
-
-       if (self != NULL) {
-               strcpy(self->name, name);
-               self->mods = RB_ROOT;
-               self->find_module = mod_dso__find_module;
-       }
-
-       return self;
-}
-
-static void mod_dso__delete_module(struct module *self)
-{
-       free(((void *)self));
-}
-
-void mod_dso__delete_modules(struct mod_dso *self)
-{
-       struct module *pos;
-       struct rb_node *next = rb_first(&self->mods);
-
-       while (next) {
-               pos = rb_entry(next, struct module, rb_node);
-               next = rb_next(&pos->rb_node);
-               rb_erase(&pos->rb_node, &self->mods);
-               mod_dso__delete_module(pos);
-       }
-}
-
-void mod_dso__delete_self(struct mod_dso *self)
-{
-       mod_dso__delete_modules(self);
-       free(self);
-}
-
-static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
-{
-       struct rb_node **p = &self->mods.rb_node;
-       struct rb_node *parent = NULL;
-       const u64 hash = mod->hash;
-       struct module *m;
-
-       while (*p != NULL) {
-               parent = *p;
-               m = rb_entry(parent, struct module, rb_node);
-               if (hash < m->hash)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-       rb_link_node(&mod->rb_node, parent, p);
-       rb_insert_color(&mod->rb_node, &self->mods);
-}
-
-struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
-{
-       struct rb_node *n;
-       u64 hash;
-       int len;
-
-       if (self == NULL)
-               return NULL;
-
-       len = strlen(name);
-       hash = crc32(name, len);
-
-       n = self->mods.rb_node;
-
-       while (n) {
-               struct module *m = rb_entry(n, struct module, rb_node);
-
-               if (hash < m->hash)
-                       n = n->rb_left;
-               else if (hash > m->hash)
-                       n = n->rb_right;
-               else {
-                       if (!strcmp(name, m->name))
-                               return m;
-                       else
-                               n = rb_next(&m->rb_node);
-               }
-       }
-
-       return NULL;
-}
-
-static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
-{
-       return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
-}
-
-size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
-{
-       struct rb_node *nd;
-       size_t ret;
-
-       ret = fprintf(fp, "dso: %s\n", self->name);
-
-       for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
-               struct module *pos = rb_entry(nd, struct module, rb_node);
-
-               ret += mod_dso__fprintf_module(pos, fp);
-       }
-
-       return ret;
-}
-
-static struct module *module__new(const char *name, const char *path)
-{
-       struct module *self = calloc(1, sizeof(*self));
-
-       if (!self)
-               goto out_failure;
-
-       self->name = calloc(1, strlen(name) + 1);
-       if (!self->name)
-               goto out_failure;
-
-       self->path = calloc(1, strlen(path) + 1);
-       if (!self->path)
-               goto out_failure;
-
-       strcpy(self->name, name);
-       strcpy(self->path, path);
-       self->hash = crc32(self->name, strlen(name));
-
-       return self;
-
-out_failure:
-       if (self) {
-               if (self->name)
-                       free(self->name);
-               if (self->path)
-                       free(self->path);
-               free(self);
-       }
-
-       return NULL;
-}
-
-static int mod_dso__load_sections(struct module *mod)
-{
-       int count = 0, path_len;
-       struct dirent *entry;
-       char *line = NULL;
-       char *dir_path;
-       DIR *dir;
-       size_t n;
-
-       path_len = strlen("/sys/module/");
-       path_len += strlen(mod->name);
-       path_len += strlen("/sections/");
-
-       dir_path = calloc(1, path_len + 1);
-       if (dir_path == NULL)
-               goto out_failure;
-
-       strcat(dir_path, "/sys/module/");
-       strcat(dir_path, mod->name);
-       strcat(dir_path, "/sections/");
-
-       dir = opendir(dir_path);
-       if (dir == NULL)
-               goto out_free;
-
-       while ((entry = readdir(dir))) {
-               struct section *section;
-               char *path, *vma;
-               int line_len;
-               FILE *file;
-
-               if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
-                       continue;
-
-               path = calloc(1, path_len + strlen(entry->d_name) + 1);
-               if (path == NULL)
-                       break;
-               strcat(path, dir_path);
-               strcat(path, entry->d_name);
-
-               file = fopen(path, "r");
-               if (file == NULL) {
-                       free(path);
-                       break;
-               }
-
-               line_len = getline(&line, &n, file);
-               if (line_len < 0) {
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-
-               if (!line) {
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-
-               line[--line_len] = '\0'; /* \n */
-
-               vma = strstr(line, "0x");
-               if (!vma) {
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-               vma += 2;
-
-               section = section__new(entry->d_name, path);
-               if (!section) {
-                       fprintf(stderr, "load_sections: allocation error\n");
-                       free(path);
-                       fclose(file);
-                       break;
-               }
-
-               hex2u64(vma, &section->vma);
-               sec_dso__insert_section(mod->sections, section);
-
-               free(path);
-               fclose(file);
-               count++;
-       }
-
-       closedir(dir);
-       free(line);
-       free(dir_path);
-
-       return count;
-
-out_free:
-       free(dir_path);
-
-out_failure:
-       return count;
-}
-
-static int mod_dso__load_module_paths(struct mod_dso *self)
-{
-       struct utsname uts;
-       int count = 0, len, err = -1;
-       char *line = NULL;
-       FILE *file;
-       char *dpath, *dir;
-       size_t n;
-
-       if (uname(&uts) < 0)
-               return err;
-
-       len = strlen("/lib/modules/");
-       len += strlen(uts.release);
-       len += strlen("/modules.dep");
-
-       dpath = calloc(1, len + 1);
-       if (dpath == NULL)
-               return err;
-
-       strcat(dpath, "/lib/modules/");
-       strcat(dpath, uts.release);
-       strcat(dpath, "/modules.dep");
-
-       file = fopen(dpath, "r");
-       if (file == NULL)
-               goto out_failure;
-
-       dir = dirname(dpath);
-       if (!dir)
-               goto out_failure;
-       strcat(dir, "/");
-
-       while (!feof(file)) {
-               struct module *module;
-               char *name, *path, *tmp;
-               FILE *modfile;
-               int line_len;
-
-               line_len = getline(&line, &n, file);
-               if (line_len < 0)
-                       break;
-
-               if (!line)
-                       break;
-
-               line[--line_len] = '\0'; /* \n */
-
-               path = strchr(line, ':');
-               if (!path)
-                       break;
-               *path = '\0';
-
-               path = strdup(line);
-               if (!path)
-                       break;
-
-               if (!strstr(path, dir)) {
-                       if (strncmp(path, "kernel/", 7))
-                               break;
-
-                       free(path);
-                       path = calloc(1, strlen(dir) + strlen(line) + 1);
-                       if (!path)
-                               break;
-                       strcat(path, dir);
-                       strcat(path, line);
-               }
-
-               modfile = fopen(path, "r");
-               if (modfile == NULL)
-                       break;
-               fclose(modfile);
-
-               name = strdup(path);
-               if (!name)
-                       break;
-
-               name = strtok(name, "/");
-               tmp = name;
-
-               while (tmp) {
-                       tmp = strtok(NULL, "/");
-                       if (tmp)
-                               name = tmp;
-               }
-
-               name = strsep(&name, ".");
-               if (!name)
-                       break;
-
-               /* Quirk: replace '-' with '_' in all modules */
-               for (len = strlen(name); len; len--) {
-                       if (*(name+len) == '-')
-                               *(name+len) = '_';
-               }
-
-               module = module__new(name, path);
-               if (!module)
-                       break;
-               mod_dso__insert_module(self, module);
-
-               module->sections = sec_dso__new_dso("sections");
-               if (!module->sections)
-                       break;
-
-               module->active = mod_dso__load_sections(module);
-
-               if (module->active > 0)
-                       count++;
-       }
-
-       if (feof(file))
-               err = count;
-       else
-               fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
-
-out_failure:
-       if (dpath)
-               free(dpath);
-       if (file)
-               fclose(file);
-       if (line)
-               free(line);
-
-       return err;
-}
-
-int mod_dso__load_modules(struct mod_dso *dso)
-{
-       int err;
-
-       err = mod_dso__load_module_paths(dso);
-
-       return err;
-}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644 (file)
index 8a592ef..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _PERF_MODULE_
-#define _PERF_MODULE_ 1
-
-#include <linux/types.h>
-#include "../types.h"
-#include <linux/list.h>
-#include <linux/rbtree.h>
-
-struct section {
-       struct rb_node  rb_node;
-       u64             hash;
-       u64             vma;
-       char            *name;
-       char            *path;
-};
-
-struct sec_dso {
-       struct list_head node;
-       struct rb_root   secs;
-       struct section    *(*find_section)(struct sec_dso *, const char *name);
-       char             name[0];
-};
-
-struct module {
-       struct rb_node  rb_node;
-       u64             hash;
-       char            *name;
-       char            *path;
-       struct sec_dso  *sections;
-       int             active;
-};
-
-struct mod_dso {
-       struct list_head node;
-       struct rb_root   mods;
-       struct module    *(*find_module)(struct mod_dso *, const char *name);
-       char             name[0];
-};
-
-struct sec_dso *sec_dso__new_dso(const char *name);
-void sec_dso__delete_sections(struct sec_dso *self);
-void sec_dso__delete_self(struct sec_dso *self);
-size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
-struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
-
-struct mod_dso *mod_dso__new_dso(const char *name);
-void mod_dso__delete_modules(struct mod_dso *self);
-void mod_dso__delete_self(struct mod_dso *self);
-size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
-struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
-int mod_dso__load_modules(struct mod_dso *dso);
-
-#endif /* _PERF_MODULE_ */
index 30c608112845954bb2de6a8831862830f7f4467b..8626a439033d34e94410ec7e8e7d32b47fd63d18 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PARSE_EVENTS_H
-#define _PARSE_EVENTS_H
+#ifndef __PERF_PARSE_EVENTS_H
+#define __PERF_PARSE_EVENTS_H
 /*
  * Parse symbolic events/counts passed in as options:
  */
@@ -31,4 +31,4 @@ extern char debugfs_path[];
 extern int valid_debugfs_mount(const char *debugfs);
 
 
-#endif /* _PARSE_EVENTS_H */
+#endif /* __PERF_PARSE_EVENTS_H */
index 2ee248ff27e5c5af9fe315c198308e9a2b9fa584..948805af43c21e45296c6caa8adda25106a66423 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef PARSE_OPTIONS_H
-#define PARSE_OPTIONS_H
+#ifndef __PERF_PARSE_OPTIONS_H
+#define __PERF_PARSE_OPTIONS_H
 
 enum parse_opt_type {
        /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
 
 extern const char *parse_options_fix_filename(const char *prefix, const char *file);
 
-#endif
+#endif /* __PERF_PARSE_OPTIONS_H */
index a5454a1d1c137ba3640add2945f1be186727d36c..b6a01973391975193a8d1ef1903674e2dc409016 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef QUOTE_H
-#define QUOTE_H
+#ifndef __PERF_QUOTE_H
+#define __PERF_QUOTE_H
 
 #include <stddef.h>
 #include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
 extern void python_quote_print(FILE *stream, const char *src);
 extern void tcl_quote_print(FILE *stream, const char *src);
 
-#endif
+#endif /* __PERF_QUOTE_H */
index cc1837deba88af6371785e4721f632529d19face..d79028727ce2c5dfba2317f71c67dcfa7f4f72bf 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef RUN_COMMAND_H
-#define RUN_COMMAND_H
+#ifndef __PERF_RUN_COMMAND_H
+#define __PERF_RUN_COMMAND_H
 
 enum {
        ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
 int start_async(struct async *async);
 int finish_async(struct async *async);
 
-#endif
+#endif /* __PERF_RUN_COMMAND_H */
index 618083bce0c66a551fd4d894b31520a67b25bac9..1a53c11265fdda78357112f3c3e7bd72a936afe8 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef SIGCHAIN_H
-#define SIGCHAIN_H
+#ifndef __PERF_SIGCHAIN_H
+#define __PERF_SIGCHAIN_H
 
 typedef void (*sigchain_fun)(int);
 
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
 
 void sigchain_push_common(sigchain_fun f);
 
-#endif /* SIGCHAIN_H */
+#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644 (file)
index 0000000..40c9acd
--- /dev/null
@@ -0,0 +1,276 @@
+#include "sort.h"
+
+regex_t                parent_regex;
+char           default_parent_pattern[] = "^sys_|^do_page_fault";
+char           *parent_pattern = default_parent_pattern;
+char           default_sort_order[] = "comm,dso,symbol";
+char           *sort_order = default_sort_order;
+int sort__need_collapse = 0;
+int sort__has_parent = 0;
+
+unsigned int dsos__col_width;
+unsigned int comms__col_width;
+unsigned int threads__col_width;
+static unsigned int parent_symbol__col_width;
+char * field_sep;
+
+LIST_HEAD(hist_entry__sort_list);
+
+struct sort_entry sort_thread = {
+       .header = "Command:  Pid",
+       .cmp    = sort__thread_cmp,
+       .print  = sort__thread_print,
+       .width  = &threads__col_width,
+};
+
+struct sort_entry sort_comm = {
+       .header         = "Command",
+       .cmp            = sort__comm_cmp,
+       .collapse       = sort__comm_collapse,
+       .print          = sort__comm_print,
+       .width          = &comms__col_width,
+};
+
+struct sort_entry sort_dso = {
+       .header = "Shared Object",
+       .cmp    = sort__dso_cmp,
+       .print  = sort__dso_print,
+       .width  = &dsos__col_width,
+};
+
+struct sort_entry sort_sym = {
+       .header = "Symbol",
+       .cmp    = sort__sym_cmp,
+       .print  = sort__sym_print,
+};
+
+struct sort_entry sort_parent = {
+       .header = "Parent symbol",
+       .cmp    = sort__parent_cmp,
+       .print  = sort__parent_print,
+       .width  = &parent_symbol__col_width,
+};
+
+struct sort_dimension {
+       const char              *name;
+       struct sort_entry       *entry;
+       int                     taken;
+};
+
+static struct sort_dimension sort_dimensions[] = {
+       { .name = "pid",        .entry = &sort_thread,  },
+       { .name = "comm",       .entry = &sort_comm,    },
+       { .name = "dso",        .entry = &sort_dso,     },
+       { .name = "symbol",     .entry = &sort_sym,     },
+       { .name = "parent",     .entry = &sort_parent,  },
+};
+
+int64_t cmp_null(void *l, void *r)
+{
+       if (!l && !r)
+               return 0;
+       else if (!l)
+               return -1;
+       else
+               return 1;
+}
+
+/* --sort pid */
+
+int64_t
+sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return right->thread->pid - left->thread->pid;
+}
+
+int repsep_fprintf(FILE *fp, const char *fmt, ...)
+{
+       int n;
+       va_list ap;
+
+       va_start(ap, fmt);
+       if (!field_sep)
+               n = vfprintf(fp, fmt, ap);
+       else {
+               char *bf = NULL;
+               n = vasprintf(&bf, fmt, ap);
+               if (n > 0) {
+                       char *sep = bf;
+
+                       while (1) {
+                               sep = strchr(sep, *field_sep);
+                               if (sep == NULL)
+                                       break;
+                               *sep = '.';
+                       }
+               }
+               fputs(bf, fp);
+               free(bf);
+       }
+       va_end(ap);
+       return n;
+}
+
+size_t
+sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       return repsep_fprintf(fp, "%*s:%5d", width - 6,
+                             self->thread->comm ?: "", self->thread->pid);
+}
+
+size_t
+sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       return repsep_fprintf(fp, "%*s", width, self->thread->comm);
+}
+
+/* --sort dso */
+
+int64_t
+sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct dso *dso_l = left->map ? left->map->dso : NULL;
+       struct dso *dso_r = right->map ? right->map->dso : NULL;
+       const char *dso_name_l, *dso_name_r;
+
+       if (!dso_l || !dso_r)
+               return cmp_null(dso_l, dso_r);
+
+       if (verbose) {
+               dso_name_l = dso_l->long_name;
+               dso_name_r = dso_r->long_name;
+       } else {
+               dso_name_l = dso_l->short_name;
+               dso_name_r = dso_r->short_name;
+       }
+
+       return strcmp(dso_name_l, dso_name_r);
+}
+
+size_t
+sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       if (self->map && self->map->dso) {
+               const char *dso_name = !verbose ? self->map->dso->short_name :
+                                                 self->map->dso->long_name;
+               return repsep_fprintf(fp, "%-*s", width, dso_name);
+       }
+
+       return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
+}
+
+/* --sort symbol */
+
+int64_t
+sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       u64 ip_l, ip_r;
+
+       if (left->sym == right->sym)
+               return 0;
+
+       ip_l = left->sym ? left->sym->start : left->ip;
+       ip_r = right->sym ? right->sym->start : right->ip;
+
+       return (int64_t)(ip_r - ip_l);
+}
+
+
+size_t
+sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
+{
+       size_t ret = 0;
+
+       if (verbose) {
+               char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
+               ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
+       }
+
+       ret += repsep_fprintf(fp, "[%c] ", self->level);
+       if (self->sym)
+               ret += repsep_fprintf(fp, "%s", self->sym->name);
+       else
+               ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
+
+       return ret;
+}
+
+/* --sort comm */
+
+int64_t
+sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return right->thread->pid - left->thread->pid;
+}
+
+int64_t
+sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
+{
+       char *comm_l = left->thread->comm;
+       char *comm_r = right->thread->comm;
+
+       if (!comm_l || !comm_r)
+               return cmp_null(comm_l, comm_r);
+
+       return strcmp(comm_l, comm_r);
+}
+
+/* --sort parent */
+
+int64_t
+sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       struct symbol *sym_l = left->parent;
+       struct symbol *sym_r = right->parent;
+
+       if (!sym_l || !sym_r)
+               return cmp_null(sym_l, sym_r);
+
+       return strcmp(sym_l->name, sym_r->name);
+}
+
+size_t
+sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
+{
+       return repsep_fprintf(fp, "%-*s", width,
+                             self->parent ? self->parent->name : "[other]");
+}
+
+int sort_dimension__add(const char *tok)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
+               struct sort_dimension *sd = &sort_dimensions[i];
+
+               if (sd->taken)
+                       continue;
+
+               if (strncasecmp(tok, sd->name, strlen(tok)))
+                       continue;
+
+               if (sd->entry->collapse)
+                       sort__need_collapse = 1;
+
+               if (sd->entry == &sort_parent) {
+                       int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
+                       if (ret) {
+                               char err[BUFSIZ];
+
+                               regerror(ret, &parent_regex, err, sizeof(err));
+                               fprintf(stderr, "Invalid regex: %s\n%s",
+                                       parent_pattern, err);
+                               exit(-1);
+                       }
+                       sort__has_parent = 1;
+               }
+
+               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
+               sd->taken = 1;
+
+               return 0;
+       }
+
+       return -ESRCH;
+}
+
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644 (file)
index 0000000..13806d7
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef __PERF_SORT_H
+#define __PERF_SORT_H
+#include "../builtin.h"
+
+#include "util.h"
+
+#include "color.h"
+#include <linux/list.h>
+#include "cache.h"
+#include <linux/rbtree.h>
+#include "symbol.h"
+#include "string.h"
+#include "callchain.h"
+#include "strlist.h"
+#include "values.h"
+
+#include "../perf.h"
+#include "debug.h"
+#include "header.h"
+
+#include "parse-options.h"
+#include "parse-events.h"
+
+#include "thread.h"
+#include "sort.h"
+
+extern regex_t parent_regex;
+extern char *sort_order;
+extern char default_parent_pattern[];
+extern char *parent_pattern;
+extern char default_sort_order[];
+extern int sort__need_collapse;
+extern int sort__has_parent;
+extern char *field_sep;
+extern struct sort_entry sort_comm;
+extern struct sort_entry sort_dso;
+extern struct sort_entry sort_sym;
+extern struct sort_entry sort_parent;
+extern unsigned int dsos__col_width;
+extern unsigned int comms__col_width;
+extern unsigned int threads__col_width;
+
+struct hist_entry {
+       struct rb_node          rb_node;
+       u64                     count;
+       struct thread           *thread;
+       struct map              *map;
+       struct symbol           *sym;
+       u64                     ip;
+       char                    level;
+       struct symbol           *parent;
+       struct callchain_node   callchain;
+       struct rb_root          sorted_chain;
+};
+
+/*
+ * configurable sorting bits
+ */
+
+struct sort_entry {
+       struct list_head list;
+
+       const char *header;
+
+       int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
+       int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
+       size_t  (*print)(FILE *fp, struct hist_entry *, unsigned int width);
+       unsigned int *width;
+       bool    elide;
+};
+
+extern struct sort_entry sort_thread;
+extern struct list_head hist_entry__sort_list;
+
+extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
+extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
+extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
+extern int64_t cmp_null(void *, void *);
+extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
+extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
+extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
+extern int sort_dimension__add(const char *);
+
+#endif /* __PERF_SORT_H */
index d2aa86c014c1b9a3882cfd924affaa116a122e79..a3d121d6c83e1d64355ef0cc6bc4c8595110a9fd 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef STRBUF_H
-#define STRBUF_H
+#ifndef __PERF_STRBUF_H
+#define __PERF_STRBUF_H
 
 /*
  * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
 extern int strbuf_branchname(struct strbuf *sb, const char *name);
 extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
-#endif /* STRBUF_H */
+#endif /* __PERF_STRBUF_H */
index c93eca9a7be39f67c5c3638d5d6ddc13770457dd..04743d3e903922ff5d3c3308380ace0196d6a4f4 100644 (file)
@@ -1,3 +1,4 @@
+#include <string.h>
 #include "string.h"
 
 static int hex(char ch)
@@ -32,3 +33,13 @@ int hex2u64(const char *ptr, u64 *long_val)
 
        return p - ptr;
 }
+
+char *strxfrchar(char *s, char from, char to)
+{
+       char *p = s;
+
+       while ((p = strchr(p, from)) != NULL)
+               *p++ = to;
+
+       return s;
+}
index bf39dfadfd24dd00fe845f1c321bf0994ad768b0..2c84bf65ba0fac020c2df05732b4b7ee0d6afabc 100644 (file)
@@ -1,11 +1,12 @@
-#ifndef _PERF_STRING_H_
-#define _PERF_STRING_H_
+#ifndef __PERF_STRING_H_
+#define __PERF_STRING_H_
 
 #include "types.h"
 
 int hex2u64(const char *ptr, u64 *val);
+char *strxfrchar(char *s, char from, char to);
 
 #define _STR(x) #x
 #define STR(x) _STR(x)
 
-#endif
+#endif /* __PERF_STRING_H */
index 921818e44a542e9aa1f8398d950121cb39fb5c24..cb4659306d7bd02221091716e6cc4151d560d1ef 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef STRLIST_H_
-#define STRLIST_H_
+#ifndef __PERF_STRLIST_H
+#define __PERF_STRLIST_H
 
 #include <linux/rbtree.h>
 #include <stdbool.h>
@@ -36,4 +36,4 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
 }
 
 int strlist__parse_list(struct strlist *self, const char *s);
-#endif /* STRLIST_H_ */
+#endif /* __PERF_STRLIST_H */
index cd93195aedb39dd9cc40abd5ccec0b58b0c8010f..e0781989cc31f5d1dd004dc66c22a584d371189d 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _INCLUDE_GUARD_SVG_HELPER_
-#define _INCLUDE_GUARD_SVG_HELPER_
+#ifndef __PERF_SVGHELPER_H
+#define __PERF_SVGHELPER_H
 
 #include "types.h"
 
@@ -25,4 +25,4 @@ extern void svg_close(void);
 
 extern int svg_page_width;
 
-#endif
+#endif /* __PERF_SVGHELPER_H */
index 47ea0609a76022259d188a85908a6c3d9572fc7f..582ce72ca4d2df310e9e05658ab910ee1bf5128a 100644 (file)
@@ -2,12 +2,14 @@
 #include "../perf.h"
 #include "string.h"
 #include "symbol.h"
+#include "thread.h"
 
 #include "debug.h"
 
 #include <libelf.h>
 #include <gelf.h>
 #include <elf.h>
+#include <sys/utsname.h>
 
 const char *sym_hist_filter;
 
@@ -18,12 +20,53 @@ enum dso_origin {
        DSO__ORIG_UBUNTU,
        DSO__ORIG_BUILDID,
        DSO__ORIG_DSO,
+       DSO__ORIG_KMODULE,
        DSO__ORIG_NOT_FOUND,
 };
 
-static struct symbol *symbol__new(u64 start, u64 len,
-                                 const char *name, unsigned int priv_size,
-                                 u64 obj_start, int v)
+static void dsos__add(struct dso *dso);
+static struct dso *dsos__find(const char *name);
+
+static struct rb_root kernel_maps;
+
+static void dso__set_symbols_end(struct dso *self)
+{
+       struct rb_node *nd, *prevnd = rb_first(&self->syms);
+
+       if (prevnd == NULL)
+               return;
+
+       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+               struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
+                             *curr = rb_entry(nd, struct symbol, rb_node);
+
+               if (prev->end == prev->start)
+                       prev->end = curr->start - 1;
+               prevnd = nd;
+       }
+}
+
+static void kernel_maps__fixup_sym_end(void)
+{
+       struct map *prev, *curr;
+       struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
+
+       if (prevnd == NULL)
+               return;
+
+       curr = rb_entry(prevnd, struct map, rb_node);
+       dso__set_symbols_end(curr->dso);
+
+       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+               prev = curr;
+               curr = rb_entry(nd, struct map, rb_node);
+               prev->end = curr->start - 1;
+               dso__set_symbols_end(curr->dso);
+       }
+}
+
+static struct symbol *symbol__new(u64 start, u64 len, const char *name,
+                                 unsigned int priv_size, int v)
 {
        size_t namelen = strlen(name) + 1;
        struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -32,10 +75,9 @@ static struct symbol *symbol__new(u64 start, u64 len,
                return NULL;
 
        if (v >= 2)
-               printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
-                       (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
+               printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n",
+                       start, (unsigned long)len, name, self->hist);
 
-       self->obj_start= obj_start;
        self->hist = NULL;
        self->hist_sum = 0;
 
@@ -60,12 +102,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
 
 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
 {
-       if (!self->module)
-               return fprintf(fp, " %llx-%llx %s\n",
+       return fprintf(fp, " %llx-%llx %s\n",
                       self->start, self->end, self->name);
-       else
-               return fprintf(fp, " %llx-%llx %s \t[%s]\n",
-                      self->start, self->end, self->name, self->module->name);
 }
 
 struct dso *dso__new(const char *name, unsigned int sym_priv_size)
@@ -74,6 +112,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
 
        if (self != NULL) {
                strcpy(self->name, name);
+               self->long_name = self->name;
+               self->short_name = self->name;
                self->syms = RB_ROOT;
                self->sym_priv_size = sym_priv_size;
                self->find_symbol = dso__find_symbol;
@@ -100,6 +140,8 @@ static void dso__delete_symbols(struct dso *self)
 void dso__delete(struct dso *self)
 {
        dso__delete_symbols(self);
+       if (self->long_name != self->name)
+               free(self->long_name);
        free(self);
 }
 
@@ -147,7 +189,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
 
 size_t dso__fprintf(struct dso *self, FILE *fp)
 {
-       size_t ret = fprintf(fp, "dso: %s\n", self->name);
+       size_t ret = fprintf(fp, "dso: %s\n", self->short_name);
 
        struct rb_node *nd;
        for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
@@ -158,9 +200,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
        return ret;
 }
 
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
+static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
 {
-       struct rb_node *nd, *prevnd;
+       struct map *map = kernel_map;
        char *line = NULL;
        size_t n;
        FILE *file = fopen("/proc/kallsyms", "r");
@@ -174,6 +216,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
                struct symbol *sym;
                int line_len, len;
                char symbol_type;
+               char *module, *symbol_name;
 
                line_len = getline(&line, &n, file);
                if (line_len < 0)
@@ -196,40 +239,50 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
                 */
                if (symbol_type != 'T' && symbol_type != 'W')
                        continue;
+
+               symbol_name = line + len + 2;
+               module = strchr(symbol_name, '\t');
+               if (module) {
+                       char *module_name_end;
+
+                       if (!use_modules)
+                               continue;
+                       *module = '\0';
+                       module = strchr(module + 1, '[');
+                       if (!module)
+                               continue;
+                       module_name_end = strchr(module + 1, ']');
+                       if (!module_name_end)
+                               continue;
+                       *(module_name_end + 1) = '\0';
+                       if (strcmp(map->dso->name, module)) {
+                               map = kernel_maps__find_by_dso_name(module);
+                               if (!map) {
+                                       fputs("/proc/{kallsyms,modules} "
+                                             "inconsistency!\n", stderr);
+                                       return -1;
+                               }
+                       }
+                       start = map->map_ip(map, start);
+               } else
+                       map = kernel_map;
                /*
                 * Well fix up the end later, when we have all sorted.
                 */
-               sym = symbol__new(start, 0xdead, line + len + 2,
-                                 self->sym_priv_size, 0, v);
+               sym = symbol__new(start, 0, symbol_name,
+                                 map->dso->sym_priv_size, v);
 
                if (sym == NULL)
                        goto out_delete_line;
 
-               if (filter && filter(self, sym))
-                       symbol__delete(sym, self->sym_priv_size);
+               if (filter && filter(map, sym))
+                       symbol__delete(sym, map->dso->sym_priv_size);
                else {
-                       dso__insert_symbol(self, sym);
+                       dso__insert_symbol(map->dso, sym);
                        count++;
                }
        }
 
-       /*
-        * Now that we have all sorted out, just set the ->end of all
-        * symbols
-        */
-       prevnd = rb_first(&self->syms);
-
-       if (prevnd == NULL)
-               goto out_delete_line;
-
-       for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
-               struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
-                             *curr = rb_entry(nd, struct symbol, rb_node);
-
-               prev->end = curr->start - 1;
-               prevnd = nd;
-       }
-
        free(line);
        fclose(file);
 
@@ -241,14 +294,33 @@ out_failure:
        return -1;
 }
 
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
+static size_t kernel_maps__fprintf(FILE *fp)
+{
+       size_t printed = fprintf(stderr, "Kernel maps:\n");
+       struct rb_node *nd;
+
+       printed += map__fprintf(kernel_map, fp);
+       printed += dso__fprintf(kernel_map->dso, fp);
+
+       for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+               struct map *pos = rb_entry(nd, struct map, rb_node);
+
+               printed += map__fprintf(pos, fp);
+               printed += dso__fprintf(pos->dso, fp);
+       }
+
+       return printed + fprintf(stderr, "END kernel maps\n");
+}
+
+static int dso__load_perf_map(struct dso *self, struct map *map,
+                             symbol_filter_t filter, int v)
 {
        char *line = NULL;
        size_t n;
        FILE *file;
        int nr_syms = 0;
 
-       file = fopen(self->name, "r");
+       file = fopen(self->long_name, "r");
        if (file == NULL)
                goto out_failure;
 
@@ -279,12 +351,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
                        continue;
 
                sym = symbol__new(start, size, line + len,
-                                 self->sym_priv_size, start, v);
+                                 self->sym_priv_size, v);
 
                if (sym == NULL)
                        goto out_delete_line;
 
-               if (filter && filter(self, sym))
+               if (filter && filter(map, sym))
                        symbol__delete(sym, self->sym_priv_size);
                else {
                        dso__insert_symbol(self, sym);
@@ -409,7 +481,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
        Elf *elf;
        int nr = 0, symidx, fd, err = 0;
 
-       fd = open(self->name, O_RDONLY);
+       fd = open(self->long_name, O_RDONLY);
        if (fd < 0)
                goto out;
 
@@ -477,7 +549,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
                                 "%s@plt", elf_sym__name(&sym, symstrs));
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-                                       sympltname, self->sym_priv_size, 0, v);
+                                       sympltname, self->sym_priv_size, v);
                        if (!f)
                                goto out_elf_end;
 
@@ -495,7 +567,7 @@ static int dso__synthesize_plt_symbols(struct  dso *self, int v)
                                 "%s@plt", elf_sym__name(&sym, symstrs));
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
-                                       sympltname, self->sym_priv_size, 0, v);
+                                       sympltname, self->sym_priv_size, v);
                        if (!f)
                                goto out_elf_end;
 
@@ -514,12 +586,13 @@ out_close:
                return nr;
 out:
        fprintf(stderr, "%s: problems reading %s PLT info.\n",
-               __func__, self->name);
+               __func__, self->long_name);
        return 0;
 }
 
-static int dso__load_sym(struct dso *self, int fd, const char *name,
-                        symbol_filter_t filter, int v, struct module *mod)
+static int dso__load_sym(struct dso *self, struct map *map, const char *name,
+                        int fd, symbol_filter_t filter, int kernel,
+                        int kmodule, int v)
 {
        Elf_Data *symstrs, *secstrs;
        uint32_t nr_syms;
@@ -531,7 +604,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
        GElf_Sym sym;
        Elf_Scn *sec, *sec_strndx;
        Elf *elf;
-       int nr = 0, kernel = !strcmp("[kernel]", self->name);
+       int nr = 0;
 
        elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
        if (elf == NULL) {
@@ -588,10 +661,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                struct symbol *f;
                const char *elf_name;
                char *demangled;
-               u64 obj_start;
-               struct section *section = NULL;
                int is_label = elf_sym__is_label(&sym);
                const char *section_name;
+               u64 sh_offset = 0;
 
                if (!is_label && !elf_sym__is_function(&sym))
                        continue;
@@ -606,7 +678,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                        continue;
 
                section_name = elf_sec__name(&shdr, secstrs);
-               obj_start = sym.st_value;
+
+               if ((kernel || kmodule)) {
+                       if (strstr(section_name, ".init"))
+                               sh_offset = shdr.sh_offset;
+               }
 
                if (self->adjust_symbols) {
                        if (v >= 2)
@@ -615,17 +691,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
 
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
-
-               if (mod) {
-                       section = mod->sections->find_section(mod->sections, section_name);
-                       if (section)
-                               sym.st_value += section->vma;
-                       else {
-                               fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
-                                       mod->name, section_name);
-                               goto out_elf_end;
-                       }
-               }
                /*
                 * We need to figure out if the object was created from C++ sources
                 * DWARF DW_compile_unit has this, but we don't always have access
@@ -636,16 +701,15 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
                if (demangled != NULL)
                        elf_name = demangled;
 
-               f = symbol__new(sym.st_value, sym.st_size, elf_name,
-                               self->sym_priv_size, obj_start, v);
+               f = symbol__new(sym.st_value + sh_offset, sym.st_size, elf_name,
+                               self->sym_priv_size, v);
                free(demangled);
                if (!f)
                        goto out_elf_end;
 
-               if (filter && filter(self, f))
+               if (filter && filter(map, f))
                        symbol__delete(f, self->sym_priv_size);
                else {
-                       f->module = mod;
                        dso__insert_symbol(self, f);
                        nr++;
                }
@@ -670,7 +734,7 @@ static char *dso__read_build_id(struct dso *self, int v)
        char *build_id = NULL, *bid;
        unsigned char *raw;
        Elf *elf;
-       int fd = open(self->name, O_RDONLY);
+       int fd = open(self->long_name, O_RDONLY);
 
        if (fd < 0)
                goto out;
@@ -679,7 +743,7 @@ static char *dso__read_build_id(struct dso *self, int v)
        if (elf == NULL) {
                if (v)
                        fprintf(stderr, "%s: cannot read %s ELF file.\n",
-                               __func__, self->name);
+                               __func__, self->long_name);
                goto out_close;
        }
 
@@ -708,7 +772,7 @@ static char *dso__read_build_id(struct dso *self, int v)
                bid += 2;
        }
        if (v >= 2)
-               printf("%s(%s): %s\n", __func__, self->name, build_id);
+               printf("%s(%s): %s\n", __func__, self->long_name, build_id);
 out_elf_end:
        elf_end(elf);
 out_close:
@@ -726,6 +790,7 @@ char dso__symtab_origin(const struct dso *self)
                [DSO__ORIG_UBUNTU] =   'u',
                [DSO__ORIG_BUILDID] =  'b',
                [DSO__ORIG_DSO] =      'd',
+               [DSO__ORIG_KMODULE] =  'K',
        };
 
        if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,7 +798,7 @@ char dso__symtab_origin(const struct dso *self)
        return origin[self->origin];
 }
 
-int dso__load(struct dso *self, symbol_filter_t filter, int v)
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v)
 {
        int size = PATH_MAX;
        char *name = malloc(size), *build_id = NULL;
@@ -746,7 +811,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v)
        self->adjust_symbols = 0;
 
        if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
-               ret = dso__load_perf_map(self, filter, v);
+               ret = dso__load_perf_map(self, map, filter, v);
                self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
                                         DSO__ORIG_NOT_FOUND;
                return ret;
@@ -759,10 +824,12 @@ more:
                self->origin++;
                switch (self->origin) {
                case DSO__ORIG_FEDORA:
-                       snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
+                       snprintf(name, size, "/usr/lib/debug%s.debug",
+                                self->long_name);
                        break;
                case DSO__ORIG_UBUNTU:
-                       snprintf(name, size, "/usr/lib/debug%s", self->name);
+                       snprintf(name, size, "/usr/lib/debug%s",
+                                self->long_name);
                        break;
                case DSO__ORIG_BUILDID:
                        build_id = dso__read_build_id(self, v);
@@ -776,7 +843,7 @@ more:
                        self->origin++;
                        /* Fall thru */
                case DSO__ORIG_DSO:
-                       snprintf(name, size, "%s", self->name);
+                       snprintf(name, size, "%s", self->long_name);
                        break;
 
                default:
@@ -786,7 +853,7 @@ more:
                fd = open(name, O_RDONLY);
        } while (fd < 0);
 
-       ret = dso__load_sym(self, fd, name, filter, v, NULL);
+       ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v);
        close(fd);
 
        /*
@@ -807,89 +874,245 @@ out:
        return ret;
 }
 
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
-                            symbol_filter_t filter, int v)
+struct map *kernel_map;
+
+static void kernel_maps__insert(struct map *map)
 {
-       struct module *mod = mod_dso__find_module(mods, name);
-       int err = 0, fd;
+       maps__insert(&kernel_maps, map);
+}
 
-       if (mod == NULL || !mod->active)
-               return err;
+struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
+{
+       /*
+        * We can't have kernel_map in kernel_maps because it spans an address
+        * space that includes the modules. The right way to fix this is to
+        * create several maps, so that we don't have overlapping ranges with
+        * modules. For now lets look first on the kernel dso.
+        */
+       struct map *map = maps__find(&kernel_maps, ip);
+       struct symbol *sym;
+
+       if (map) {
+               ip = map->map_ip(map, ip);
+               sym = map->dso->find_symbol(map->dso, ip);
+       } else {
+               map = kernel_map;
+               sym = map->dso->find_symbol(map->dso, ip);
+       }
 
-       fd = open(mod->path, O_RDONLY);
+       if (mapp)
+               *mapp = map;
 
-       if (fd < 0)
+       return sym;
+}
+
+struct map *kernel_maps__find_by_dso_name(const char *name)
+{
+       struct rb_node *nd;
+
+       for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+               struct map *map = rb_entry(nd, struct map, rb_node);
+
+               if (map->dso && strcmp(map->dso->name, name) == 0)
+                       return map;
+       }
+
+       return NULL;
+}
+
+static int dso__load_module_sym(struct dso *self, struct map *map,
+                               symbol_filter_t filter, int v)
+{
+       int err = 0, fd = open(self->long_name, O_RDONLY);
+
+       if (fd < 0) {
+               if (v)
+                       fprintf(stderr, "%s: cannot open %s\n",
+                               __func__, self->long_name);
                return err;
+       }
 
-       err = dso__load_sym(self, fd, name, filter, v, mod);
+       err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v);
        close(fd);
 
        return err;
 }
 
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
+static int dsos__load_modules_sym_dir(char *dirname,
+                                     symbol_filter_t filter, int v)
 {
-       struct mod_dso *mods = mod_dso__new_dso("modules");
-       struct module *pos;
-       struct rb_node *next;
-       int err, count = 0;
+       struct dirent *dent;
+       int nr_symbols = 0, err;
+       DIR *dir = opendir(dirname);
 
-       err = mod_dso__load_modules(mods);
+       if (!dir) {
+               if (v)
+                       fprintf(stderr, "%s: cannot open %s dir\n", __func__,
+                               dirname);
+               return -1;
+       }
 
-       if (err <= 0)
-               return err;
+       while ((dent = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+
+               if (dent->d_type == DT_DIR) {
+                       if (!strcmp(dent->d_name, ".") ||
+                           !strcmp(dent->d_name, ".."))
+                               continue;
+
+                       snprintf(path, sizeof(path), "%s/%s",
+                                dirname, dent->d_name);
+                       err = dsos__load_modules_sym_dir(path, filter, v);
+                       if (err < 0)
+                               goto failure;
+               } else {
+                       char *dot = strrchr(dent->d_name, '.'),
+                            dso_name[PATH_MAX];
+                       struct map *map;
+                       struct rb_node *last;
+
+                       if (dot == NULL || strcmp(dot, ".ko"))
+                               continue;
+                       snprintf(dso_name, sizeof(dso_name), "[%.*s]",
+                                (int)(dot - dent->d_name), dent->d_name);
+
+                       strxfrchar(dso_name, '-', '_');
+                       map = kernel_maps__find_by_dso_name(dso_name);
+                       if (map == NULL)
+                               continue;
+
+                       snprintf(path, sizeof(path), "%s/%s",
+                                dirname, dent->d_name);
+
+                       map->dso->long_name = strdup(path);
+                       if (map->dso->long_name == NULL)
+                               goto failure;
+
+                       err = dso__load_module_sym(map->dso, map, filter, v);
+                       if (err < 0)
+                               goto failure;
+                       last = rb_last(&map->dso->syms);
+                       if (last) {
+                               struct symbol *sym;
+                               sym = rb_entry(last, struct symbol, rb_node);
+                               map->end = map->start + sym->end;
+                       }
+               }
+               nr_symbols += err;
+       }
 
-       /*
-        * Iterate over modules, and load active symbols.
-        */
-       next = rb_first(&mods->mods);
-       while (next) {
-               pos = rb_entry(next, struct module, rb_node);
-               err = dso__load_module(self, mods, pos->name, filter, v);
+       return nr_symbols;
+failure:
+       closedir(dir);
+       return -1;
+}
 
-               if (err < 0)
-                       break;
+static int dsos__load_modules_sym(symbol_filter_t filter, int v)
+{
+       struct utsname uts;
+       char modules_path[PATH_MAX];
 
-               next = rb_next(&pos->rb_node);
-               count += err;
-       }
+       if (uname(&uts) < 0)
+               return -1;
 
-       if (err < 0) {
-               mod_dso__delete_modules(mods);
-               mod_dso__delete_self(mods);
-               return err;
-       }
+       snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
+                uts.release);
 
-       return count;
+       return dsos__load_modules_sym_dir(modules_path, filter, v);
 }
 
-static inline void dso__fill_symbol_holes(struct dso *self)
+/*
+ * Constructor variant for modules (where we know from /proc/modules where
+ * they are loaded) and for vmlinux, where only after we load all the
+ * symbols we'll know where it starts and ends.
+ */
+static struct map *map__new2(u64 start, struct dso *dso)
 {
-       struct symbol *prev = NULL;
-       struct rb_node *nd;
+       struct map *self = malloc(sizeof(*self));
 
-       for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
-               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+       if (self != NULL) {
+               self->start = start;
+               /*
+                * Will be filled after we load all the symbols
+                */
+               self->end = 0;
 
-               if (prev) {
-                       u64 hole = 0;
-                       int alias = pos->start == prev->start;
+               self->pgoff = 0;
+               self->dso = dso;
+               self->map_ip = map__map_ip;
+               RB_CLEAR_NODE(&self->rb_node);
+       }
+       return self;
+}
 
-                       if (!alias)
-                               hole = prev->start - pos->end - 1;
+static int dsos__load_modules(unsigned int sym_priv_size)
+{
+       char *line = NULL;
+       size_t n;
+       FILE *file = fopen("/proc/modules", "r");
+       struct map *map;
 
-                       if (hole || alias) {
-                               if (alias)
-                                       pos->end = prev->end;
-                               else if (hole)
-                                       pos->end = prev->start - 1;
-                       }
+       if (file == NULL)
+               return -1;
+
+       while (!feof(file)) {
+               char name[PATH_MAX];
+               u64 start;
+               struct dso *dso;
+               char *sep;
+               int line_len;
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0)
+                       break;
+
+               if (!line)
+                       goto out_failure;
+
+               line[--line_len] = '\0'; /* \n */
+
+               sep = strrchr(line, 'x');
+               if (sep == NULL)
+                       continue;
+
+               hex2u64(sep + 1, &start);
+
+               sep = strchr(line, ' ');
+               if (sep == NULL)
+                       continue;
+
+               *sep = '\0';
+
+               snprintf(name, sizeof(name), "[%s]", line);
+               dso = dso__new(name, sym_priv_size);
+
+               if (dso == NULL)
+                       goto out_delete_line;
+
+               map = map__new2(start, dso);
+               if (map == NULL) {
+                       dso__delete(dso);
+                       goto out_delete_line;
                }
-               prev = pos;
+
+               dso->origin = DSO__ORIG_KMODULE;
+               kernel_maps__insert(map);
+               dsos__add(dso);
        }
+
+       free(line);
+       fclose(file);
+
+       return 0;
+
+out_delete_line:
+       free(line);
+out_failure:
+       return -1;
 }
 
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
+static int dso__load_vmlinux(struct dso *self, struct map *map,
+                            const char *vmlinux,
                             symbol_filter_t filter, int v)
 {
        int err, fd = open(vmlinux, O_RDONLY);
@@ -897,47 +1120,86 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
        if (fd < 0)
                return -1;
 
-       err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
-
-       if (err > 0)
-               dso__fill_symbol_holes(self);
+       err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v);
 
        close(fd);
 
        return err;
 }
 
-int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int v, int use_modules)
+int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
+                     symbol_filter_t filter, int v, int use_modules)
 {
        int err = -1;
+       struct dso *dso = dso__new(vmlinux, sym_priv_size);
+
+       if (dso == NULL)
+               return -1;
+
+       dso->short_name = "[kernel]";
+       kernel_map = map__new2(0, dso);
+       if (kernel_map == NULL)
+               goto out_delete_dso;
+
+       kernel_map->map_ip = vdso__map_ip;
+
+       if (use_modules && dsos__load_modules(sym_priv_size) < 0) {
+               fprintf(stderr, "Failed to load list of modules in use! "
+                               "Continuing...\n");
+               use_modules = 0;
+       }
 
        if (vmlinux) {
-               err = dso__load_vmlinux(self, vmlinux, filter, v);
+               err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
                if (err > 0 && use_modules) {
-                       int syms = dso__load_modules(self, filter, v);
+                       int syms = dsos__load_modules_sym(filter, v);
 
-                       if (syms < 0) {
-                               fprintf(stderr, "dso__load_modules failed!\n");
-                               return syms;
-                       }
-                       err += syms;
+                       if (syms < 0)
+                               fprintf(stderr, "Failed to read module symbols!"
+                                       " Continuing...\n");
+                       else
+                               err += syms;
                }
        }
 
        if (err <= 0)
-               err = dso__load_kallsyms(self, filter, v);
+               err = maps__load_kallsyms(filter, use_modules, v);
 
-       if (err > 0)
-               self->origin = DSO__ORIG_KERNEL;
+       if (err > 0) {
+               struct rb_node *node = rb_first(&dso->syms);
+               struct symbol *sym = rb_entry(node, struct symbol, rb_node);
+               /*
+                * Now that we have all sorted out, just set the ->end of all
+                * symbols that still don't have it.
+                */
+               dso__set_symbols_end(dso);
+               kernel_maps__fixup_sym_end();
+
+               kernel_map->start = sym->start;
+               node = rb_last(&dso->syms);
+               sym = rb_entry(node, struct symbol, rb_node);
+               kernel_map->end = sym->end;
+
+               dso->origin = DSO__ORIG_KERNEL;
+               /*
+                * XXX See kernel_maps__find_symbol comment
+                * kernel_maps__insert(kernel_map)
+                */
+               dsos__add(dso);
+
+               if (v > 0)
+                       kernel_maps__fprintf(stderr);
+       }
 
        return err;
+
+out_delete_dso:
+       dso__delete(dso);
+       return -1;
 }
 
 LIST_HEAD(dsos);
-struct dso     *kernel_dso;
 struct dso     *vdso;
-struct dso     *hypervisor_dso;
 
 const char     *vmlinux_name = "vmlinux";
 int            modules;
@@ -969,7 +1231,7 @@ struct dso *dsos__findnew(const char *name)
        if (!dso)
                goto out_delete_dso;
 
-       nr = dso__load(dso, NULL, verbose);
+       nr = dso__load(dso, NULL, NULL, verbose);
        if (nr < 0) {
                eprintf("Failed to open: %s\n", name);
                goto out_delete_dso;
@@ -994,43 +1256,20 @@ void dsos__fprintf(FILE *fp)
                dso__fprintf(pos, fp);
 }
 
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
-{
-       return dso__find_symbol(dso, ip);
-}
-
 int load_kernel(void)
 {
-       int err;
-
-       kernel_dso = dso__new("[kernel]", 0);
-       if (!kernel_dso)
+       if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
-       if (err <= 0) {
-               dso__delete(kernel_dso);
-               kernel_dso = NULL;
-       } else
-               dsos__add(kernel_dso);
-
        vdso = dso__new("[vdso]", 0);
        if (!vdso)
                return -1;
 
-       vdso->find_symbol = vdso__find_symbol;
-
        dsos__add(vdso);
 
-       hypervisor_dso = dso__new("[hypervisor]", 0);
-       if (!hypervisor_dso)
-               return -1;
-       dsos__add(hypervisor_dso);
-
-       return err;
+       return 0;
 }
 
-
 void symbol__init(void)
 {
        elf_version(EV_CURRENT);
index 6e8490716408770b15905437bcebf07a4c89cc70..2e4522edeb078bdff3137ded45a699f2b3dbceb4 100644 (file)
@@ -1,11 +1,10 @@
-#ifndef _PERF_SYMBOL_
-#define _PERF_SYMBOL_ 1
+#ifndef __PERF_SYMBOL
+#define __PERF_SYMBOL 1
 
 #include <linux/types.h>
 #include "types.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
-#include "module.h"
 #include "event.h"
 
 #ifdef HAVE_CPLUS_DEMANGLE
@@ -36,10 +35,8 @@ struct symbol {
        struct rb_node  rb_node;
        u64             start;
        u64             end;
-       u64             obj_start;
        u64             hist_sum;
        u64             *hist;
-       struct module   *module;
        void            *priv;
        char            name[0];
 };
@@ -52,12 +49,14 @@ struct dso {
        unsigned char    adjust_symbols;
        unsigned char    slen_calculated;
        unsigned char    origin;
+       const char       *short_name;
+       char             *long_name;
        char             name[0];
 };
 
 extern const char *sym_hist_filter;
 
-typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
+typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 struct dso *dso__new(const char *name, unsigned int sym_priv_size);
 void dso__delete(struct dso *self);
@@ -69,10 +68,10 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
 
 struct symbol *dso__find_symbol(struct dso *self, u64 ip);
 
-int dso__load_kernel(struct dso *self, const char *vmlinux,
-                    symbol_filter_t filter, int verbose, int modules);
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
-int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
+int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
+                     symbol_filter_t filter, int verbose, int modules);
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter,
+             int verbose);
 struct dso *dsos__findnew(const char *name);
 void dsos__fprintf(FILE *fp);
 
@@ -84,9 +83,8 @@ int load_kernel(void);
 void symbol__init(void);
 
 extern struct list_head dsos;
-extern struct dso *kernel_dso;
+extern struct map *kernel_map;
 extern struct dso *vdso;
-extern struct dso *hypervisor_dso;
 extern const char *vmlinux_name;
 extern int   modules;
-#endif /* _PERF_SYMBOL_ */
+#endif /* __PERF_SYMBOL */
index 45efb5db0d19819f281f75b17541dd9ebb76b8ad..3b56aebb1f4bfab84b906c795fb4c91dc0bde886 100644 (file)
@@ -15,7 +15,8 @@ static struct thread *thread__new(pid_t pid)
                self->comm = malloc(32);
                if (self->comm)
                        snprintf(self->comm, 32, ":%d", self->pid);
-               INIT_LIST_HEAD(&self->maps);
+               self->maps = RB_ROOT;
+               INIT_LIST_HEAD(&self->removed_maps);
        }
 
        return self;
@@ -31,10 +32,19 @@ int thread__set_comm(struct thread *self, const char *comm)
 
 static size_t thread__fprintf(struct thread *self, FILE *fp)
 {
+       struct rb_node *nd;
        struct map *pos;
-       size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
+       size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
+                            self->pid, self->comm);
+
+       for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
+               pos = rb_entry(nd, struct map, rb_node);
+               ret += map__fprintf(pos, fp);
+       }
+
+       ret = fprintf(fp, "Removed maps:\n");
 
-       list_for_each_entry(pos, &self->maps, node)
+       list_for_each_entry(pos, &self->removed_maps, node)
                ret += map__fprintf(pos, fp);
 
        return ret;
@@ -93,42 +103,82 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
        return thread;
 }
 
-void thread__insert_map(struct thread *self, struct map *map)
+static void thread__remove_overlappings(struct thread *self, struct map *map)
 {
-       struct map *pos, *tmp;
-
-       list_for_each_entry_safe(pos, tmp, &self->maps, node) {
-               if (map__overlap(pos, map)) {
-                       if (verbose >= 2) {
-                               printf("overlapping maps:\n");
-                               map__fprintf(map, stdout);
-                               map__fprintf(pos, stdout);
-                       }
-
-                       if (map->start <= pos->start && map->end > pos->start)
-                               pos->start = map->end;
-
-                       if (map->end >= pos->end && map->start < pos->end)
-                               pos->end = map->start;
-
-                       if (verbose >= 2) {
-                               printf("after collision:\n");
-                               map__fprintf(pos, stdout);
-                       }
-
-                       if (pos->start >= pos->end) {
-                               list_del_init(&pos->node);
-                               free(pos);
-                       }
+       struct rb_node *next = rb_first(&self->maps);
+
+       while (next) {
+               struct map *pos = rb_entry(next, struct map, rb_node);
+               next = rb_next(&pos->rb_node);
+
+               if (!map__overlap(pos, map))
+                       continue;
+
+               if (verbose >= 2) {
+                       printf("overlapping maps:\n");
+                       map__fprintf(map, stdout);
+                       map__fprintf(pos, stdout);
                }
+
+               rb_erase(&pos->rb_node, &self->maps);
+               /*
+                * We may have references to this map, for instance in some
+                * hist_entry instances, so just move them to a separate
+                * list.
+                */
+               list_add_tail(&pos->node, &self->removed_maps);
+       }
+}
+
+void maps__insert(struct rb_root *maps, struct map *map)
+{
+       struct rb_node **p = &maps->rb_node;
+       struct rb_node *parent = NULL;
+       const u64 ip = map->start;
+       struct map *m;
+
+       while (*p != NULL) {
+               parent = *p;
+               m = rb_entry(parent, struct map, rb_node);
+               if (ip < m->start)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
        }
 
-       list_add_tail(&map->node, &self->maps);
+       rb_link_node(&map->rb_node, parent, p);
+       rb_insert_color(&map->rb_node, maps);
+}
+
+struct map *maps__find(struct rb_root *maps, u64 ip)
+{
+       struct rb_node **p = &maps->rb_node;
+       struct rb_node *parent = NULL;
+       struct map *m;
+
+       while (*p != NULL) {
+               parent = *p;
+               m = rb_entry(parent, struct map, rb_node);
+               if (ip < m->start)
+                       p = &(*p)->rb_left;
+               else if (ip > m->end)
+                       p = &(*p)->rb_right;
+               else
+                       return m;
+       }
+
+       return NULL;
+}
+
+void thread__insert_map(struct thread *self, struct map *map)
+{
+       thread__remove_overlappings(self, map);
+       maps__insert(&self->maps, map);
 }
 
 int thread__fork(struct thread *self, struct thread *parent)
 {
-       struct map *map;
+       struct rb_node *nd;
 
        if (self->comm)
                free(self->comm);
@@ -136,7 +186,8 @@ int thread__fork(struct thread *self, struct thread *parent)
        if (!self->comm)
                return -ENOMEM;
 
-       list_for_each_entry(map, &parent->maps, node) {
+       for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
+               struct map *map = rb_entry(nd, struct map, rb_node);
                struct map *new = map__clone(map);
                if (!new)
                        return -ENOMEM;
@@ -146,20 +197,6 @@ int thread__fork(struct thread *self, struct thread *parent)
        return 0;
 }
 
-struct map *thread__find_map(struct thread *self, u64 ip)
-{
-       struct map *pos;
-
-       if (self == NULL)
-               return NULL;
-
-       list_for_each_entry(pos, &self->maps, node)
-               if (ip >= pos->start && ip <= pos->end)
-                       return pos;
-
-       return NULL;
-}
-
 size_t threads__fprintf(FILE *fp, struct rb_root *threads)
 {
        size_t ret = 0;
index 32aea3c1c2ad6efd174f6f67843134d033853fba..845d9b62f96f9d65c9a687dc8c5c89dbc1157d1b 100644 (file)
@@ -1,11 +1,14 @@
+#ifndef __PERF_THREAD_H
+#define __PERF_THREAD_H
+
 #include <linux/rbtree.h>
-#include <linux/list.h>
 #include <unistd.h>
 #include "symbol.h"
 
 struct thread {
        struct rb_node          rb_node;
-       struct list_head        maps;
+       struct rb_root          maps;
+       struct list_head        removed_maps;
        pid_t                   pid;
        char                    shortname[3];
        char                    *comm;
@@ -18,5 +21,17 @@ struct thread *
 register_idle_thread(struct rb_root *threads, struct thread **last_match);
 void thread__insert_map(struct thread *self, struct map *map);
 int thread__fork(struct thread *self, struct thread *parent);
-struct map *thread__find_map(struct thread *self, u64 ip);
 size_t threads__fprintf(FILE *fp, struct rb_root *threads);
+
+void maps__insert(struct rb_root *maps, struct map *map);
+struct map *maps__find(struct rb_root *maps, u64 ip);
+
+struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp);
+struct map *kernel_maps__find_by_dso_name(const char *name);
+
+static inline struct map *thread__find_map(struct thread *self, u64 ip)
+{
+       return self ? maps__find(&self->maps, ip) : NULL;
+}
+
+#endif /* __PERF_THREAD_H */
index 693f815c9429ca375f74bbfc96901232aa02c48f..162c3e6deb9345616aa973bb6537f92b7375958b 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _TRACE_EVENTS_H
-#define _TRACE_EVENTS_H
+#ifndef __PERF_TRACE_EVENTS_H
+#define __PERF_TRACE_EVENTS_H
 
 #include "parse-events.h"
 
@@ -242,4 +242,4 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
 
 void read_tracing_data(struct perf_event_attr *pattrs, int nb_events);
 
-#endif /* _TRACE_EVENTS_H */
+#endif /* __PERF_TRACE_EVENTS_H */
index 5e75f9005940ac497f32ea1e12b84a9389b77ef3..7d6b8331f8984764e23260eff33d4a13ea09317f 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PERF_TYPES_H
-#define _PERF_TYPES_H
+#ifndef __PERF_TYPES_H
+#define __PERF_TYPES_H
 
 /*
  * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short     s16;
 typedef unsigned char     u8;
 typedef signed char       s8;
 
-#endif /* _PERF_TYPES_H */
+#endif /* __PERF_TYPES_H */
index cadf8cf2a590c7169a2f3be58fdd9aded515cd43..2fa967e1a88aaa0a4a4f6dfe98517be6c08c8f68 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _PERF_VALUES_H
-#define _PERF_VALUES_H
+#ifndef __PERF_VALUES_H
+#define __PERF_VALUES_H
 
 #include "types.h"
 
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
 void perf_read_values_display(FILE *fp, struct perf_read_values *values,
                              int raw);
 
-#endif /* _PERF_VALUES_H */
+#endif /* __PERF_VALUES_H */