]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - tools/perf/builtin-annotate.c
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[karo-tx-linux.git] / tools / perf / builtin-annotate.c
index 8879463807e4a06269e11e5594731ace4fd80ff2..e18eb7ed30ae3b00af785c6bef248b4714bf34f4 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "util/util.h"
 
+#include "util/util.h"
 #include "util/color.h"
 #include <linux/list.h>
 #include "util/cache.h"
@@ -18,6 +19,9 @@
 #include "perf.h"
 #include "util/debug.h"
 
+#include "util/evlist.h"
+#include "util/evsel.h"
+#include "util/annotate.h"
 #include "util/event.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -36,9 +40,13 @@ static bool          print_line;
 
 static const char *sym_hist_filter;
 
-static int hists__add_entry(struct hists *self, struct addr_location *al)
+static int perf_evlist__add_sample(struct perf_evlist *evlist,
+                                  struct perf_sample *sample,
+                                  struct perf_evsel *evsel,
+                                  struct addr_location *al)
 {
        struct hist_entry *he;
+       int ret;
 
        if (sym_hist_filter != NULL &&
            (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
@@ -51,25 +59,41 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
                return 0;
        }
 
-       he = __hists__add_entry(self, al, NULL, 1);
+       he = __hists__add_entry(&evsel->hists, al, NULL, 1);
        if (he == NULL)
                return -ENOMEM;
 
-       return hist_entry__inc_addr_samples(he, al->addr);
+       ret = 0;
+       if (he->ms.sym != NULL) {
+               struct annotation *notes = symbol__annotation(he->ms.sym);
+               if (notes->src == NULL &&
+                   symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
+                       return -ENOMEM;
+
+               ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+       }
+
+       evsel->hists.stats.total_period += sample->period;
+       hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
+       return ret;
 }
 
-static int process_sample_event(event_t *event, struct sample_data *sample,
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_evsel *evsel,
                                struct perf_session *session)
 {
        struct addr_location al;
 
-       if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
+       if (perf_event__preprocess_sample(event, session, &al, sample,
+                                         symbol__annotate_init) < 0) {
                pr_warning("problem processing %d event, skipping it.\n",
                           event->header.type);
                return -1;
        }
 
-       if (!al.filtered && hists__add_entry(&session->hists, &al)) {
+       if (!al.filtered &&
+           perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
                pr_warning("problem incrementing symbol count, "
                           "skipping event\n");
                return -1;
@@ -78,261 +102,26 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
        return 0;
 }
 
-static int objdump_line__print(struct objdump_line *self,
-                              struct list_head *head,
-                              struct hist_entry *he, u64 len)
-{
-       struct symbol *sym = he->ms.sym;
-       static const char *prev_line;
-       static const char *prev_color;
-
-       if (self->offset != -1) {
-               const char *path = NULL;
-               unsigned int hits = 0;
-               double percent = 0.0;
-               const char *color;
-               struct sym_priv *priv = symbol__priv(sym);
-               struct sym_ext *sym_ext = priv->ext;
-               struct sym_hist *h = priv->hist;
-               s64 offset = self->offset;
-               struct objdump_line *next = objdump__get_next_ip_line(head, self);
-
-               while (offset < (s64)len &&
-                      (next == NULL || offset < next->offset)) {
-                       if (sym_ext) {
-                               if (path == NULL)
-                                       path = sym_ext[offset].path;
-                               percent += sym_ext[offset].percent;
-                       } else
-                               hits += h->ip[offset];
-
-                       ++offset;
-               }
-
-               if (sym_ext == NULL && h->sum)
-                       percent = 100.0 * hits / h->sum;
-
-               color = get_percent_color(percent);
-
-               /*
-                * Also color the filename and line if needed, with
-                * the same color than the percentage. Don't print it
-                * twice for close colored ip with the same filename:line
-                */
-               if (path) {
-                       if (!prev_line || strcmp(prev_line, path)
-                                      || color != prev_color) {
-                               color_fprintf(stdout, color, " %s", path);
-                               prev_line = path;
-                               prev_color = color;
-                       }
-               }
-
-               color_fprintf(stdout, color, " %7.2f", percent);
-               printf(" :      ");
-               color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
-       } else {
-               if (!*self->line)
-                       printf("         :\n");
-               else
-                       printf("         :      %s\n", self->line);
-       }
-
-       return 0;
-}
-
-static struct rb_root root_sym_ext;
-
-static void insert_source_line(struct sym_ext *sym_ext)
-{
-       struct sym_ext *iter;
-       struct rb_node **p = &root_sym_ext.rb_node;
-       struct rb_node *parent = NULL;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct sym_ext, node);
-
-               if (sym_ext->percent > iter->percent)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&sym_ext->node, parent, p);
-       rb_insert_color(&sym_ext->node, &root_sym_ext);
-}
-
-static void free_source_line(struct hist_entry *he, int len)
-{
-       struct sym_priv *priv = symbol__priv(he->ms.sym);
-       struct sym_ext *sym_ext = priv->ext;
-       int i;
-
-       if (!sym_ext)
-               return;
-
-       for (i = 0; i < len; i++)
-               free(sym_ext[i].path);
-       free(sym_ext);
-
-       priv->ext = NULL;
-       root_sym_ext = RB_ROOT;
-}
-
-/* Get the filename:line for the colored entries */
-static void
-get_source_line(struct hist_entry *he, int len, const char *filename)
-{
-       struct symbol *sym = he->ms.sym;
-       u64 start;
-       int i;
-       char cmd[PATH_MAX * 2];
-       struct sym_ext *sym_ext;
-       struct sym_priv *priv = symbol__priv(sym);
-       struct sym_hist *h = priv->hist;
-
-       if (!h->sum)
-               return;
-
-       sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
-       if (!priv->ext)
-               return;
-
-       start = he->ms.map->unmap_ip(he->ms.map, sym->start);
-
-       for (i = 0; i < len; i++) {
-               char *path = NULL;
-               size_t line_len;
-               u64 offset;
-               FILE *fp;
-
-               sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
-               if (sym_ext[i].percent <= 0.5)
-                       continue;
-
-               offset = start + i;
-               sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
-               fp = popen(cmd, "r");
-               if (!fp)
-                       continue;
-
-               if (getline(&path, &line_len, fp) < 0 || !line_len)
-                       goto next;
-
-               sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
-               if (!sym_ext[i].path)
-                       goto next;
-
-               strcpy(sym_ext[i].path, path);
-               insert_source_line(&sym_ext[i]);
-
-       next:
-               pclose(fp);
-       }
-}
-
-static void print_summary(const char *filename)
-{
-       struct sym_ext *sym_ext;
-       struct rb_node *node;
-
-       printf("\nSorted summary for file %s\n", filename);
-       printf("----------------------------------------------\n\n");
-
-       if (RB_EMPTY_ROOT(&root_sym_ext)) {
-               printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
-               return;
-       }
-
-       node = rb_first(&root_sym_ext);
-       while (node) {
-               double percent;
-               const char *color;
-               char *path;
-
-               sym_ext = rb_entry(node, struct sym_ext, node);
-               percent = sym_ext->percent;
-               color = get_percent_color(percent);
-               path = sym_ext->path;
-
-               color_fprintf(stdout, color, " %7.2f %s", percent, path);
-               node = rb_next(node);
-       }
-}
-
-static void hist_entry__print_hits(struct hist_entry *self)
-{
-       struct symbol *sym = self->ms.sym;
-       struct sym_priv *priv = symbol__priv(sym);
-       struct sym_hist *h = priv->hist;
-       u64 len = sym->end - sym->start, offset;
-
-       for (offset = 0; offset < len; ++offset)
-               if (h->ip[offset] != 0)
-                       printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
-                              sym->start + offset, h->ip[offset]);
-       printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
-}
-
-static int hist_entry__tty_annotate(struct hist_entry *he)
+static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
 {
-       struct map *map = he->ms.map;
-       struct dso *dso = map->dso;
-       struct symbol *sym = he->ms.sym;
-       const char *filename = dso->long_name, *d_filename;
-       u64 len;
-       LIST_HEAD(head);
-       struct objdump_line *pos, *n;
-
-       if (hist_entry__annotate(he, &head, 0) < 0)
-               return -1;
-
-       if (full_paths)
-               d_filename = filename;
-       else
-               d_filename = basename(filename);
-
-       len = sym->end - sym->start;
-
-       if (print_line) {
-               get_source_line(he, len, filename);
-               print_summary(filename);
-       }
-
-       printf("\n\n------------------------------------------------\n");
-       printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
-       printf("------------------------------------------------\n");
-
-       if (verbose)
-               hist_entry__print_hits(he);
-
-       list_for_each_entry_safe(pos, n, &head, node) {
-               objdump_line__print(pos, &head, he, len);
-               list_del(&pos->node);
-               objdump_line__free(pos);
-       }
-
-       if (print_line)
-               free_source_line(he, len);
-
-       return 0;
+       return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
+                                   print_line, full_paths, 0, 0);
 }
 
-static void hists__find_annotations(struct hists *self)
+static void hists__find_annotations(struct hists *self, int evidx)
 {
        struct rb_node *nd = rb_first(&self->entries), *next;
        int key = KEY_RIGHT;
 
        while (nd) {
                struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
-               struct sym_priv *priv;
+               struct annotation *notes;
 
                if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
                        goto find_next;
 
-               priv = symbol__priv(he->ms.sym);
-               if (priv->hist == NULL) {
+               notes = symbol__annotation(he->ms.sym);
+               if (notes->src == NULL) {
 find_next:
                        if (key == KEY_LEFT)
                                nd = rb_prev(nd);
@@ -342,7 +131,7 @@ find_next:
                }
 
                if (use_browser > 0) {
-                       key = hist_entry__tui_annotate(he);
+                       key = hist_entry__tui_annotate(he, evidx);
                        switch (key) {
                        case KEY_RIGHT:
                                next = rb_next(nd);
@@ -357,24 +146,24 @@ find_next:
                        if (next != NULL)
                                nd = next;
                } else {
-                       hist_entry__tty_annotate(he);
+                       hist_entry__tty_annotate(he, evidx);
                        nd = rb_next(nd);
                        /*
                         * Since we have a hist_entry per IP for the same
-                        * symbol, free he->ms.sym->hist to signal we already
+                        * symbol, free he->ms.sym->src to signal we already
                         * processed this symbol.
                         */
-                       free(priv->hist);
-                       priv->hist = NULL;
+                       free(notes->src);
+                       notes->src = NULL;
                }
        }
 }
 
 static struct perf_event_ops event_ops = {
        .sample = process_sample_event,
-       .mmap   = event__process_mmap,
-       .comm   = event__process_comm,
-       .fork   = event__process_task,
+       .mmap   = perf_event__process_mmap,
+       .comm   = perf_event__process_comm,
+       .fork   = perf_event__process_task,
        .ordered_samples = true,
        .ordering_requires_timestamps = true,
 };
@@ -383,6 +172,8 @@ static int __cmd_annotate(void)
 {
        int ret;
        struct perf_session *session;
+       struct perf_evsel *pos;
+       u64 total_nr_samples;
 
        session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
        if (session == NULL)
@@ -403,12 +194,36 @@ static int __cmd_annotate(void)
        if (verbose > 2)
                perf_session__fprintf_dsos(session, stdout);
 
-       hists__collapse_resort(&session->hists);
-       hists__output_resort(&session->hists);
-       hists__find_annotations(&session->hists);
-out_delete:
-       perf_session__delete(session);
+       total_nr_samples = 0;
+       list_for_each_entry(pos, &session->evlist->entries, node) {
+               struct hists *hists = &pos->hists;
+               u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
 
+               if (nr_samples > 0) {
+                       total_nr_samples += nr_samples;
+                       hists__collapse_resort(hists);
+                       hists__output_resort(hists);
+                       hists__find_annotations(hists, pos->idx);
+               }
+       }
+
+       if (total_nr_samples == 0) {
+               ui__warning("The %s file has no samples!\n", input_name);
+               goto out_delete;
+       }
+out_delete:
+       /*
+        * Speed up the exit process, for large files this can
+        * take quite a while.
+        *
+        * XXX Enable this when using valgrind or if we ever
+        * librarize this command.
+        *
+        * Also experiment with obstacks to see how much speed
+        * up we'll get here.
+        *
+        * perf_session__delete(session);
+        */
        return ret;
 }
 
@@ -451,9 +266,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
        else if (use_tui)
                use_browser = 1;
 
-       setup_browser();
+       setup_browser(true);
 
-       symbol_conf.priv_size = sizeof(struct sym_priv);
+       symbol_conf.priv_size = sizeof(struct annotation);
        symbol_conf.try_vmlinux_path = true;
 
        if (symbol__init() < 0)