Merge branch 'nfs-for-2.6.32'
[pandora-kernel.git] / tools / perf / builtin-annotate.c
index 7e58e3a..5e17de9 100644 (file)
@@ -10,9 +10,9 @@
 #include "util/util.h"
 
 #include "util/color.h"
-#include "util/list.h"
+#include <linux/list.h>
 #include "util/cache.h"
-#include "util/rbtree.h"
+#include <linux/rbtree.h>
 #include "util/symbol.h"
 #include "util/string.h"
 
 #define SHOW_USER      2
 #define SHOW_HV                4
 
-#define MIN_GREEN              0.5
-#define MIN_RED                5.0
-
-
 static char            const *input_name = "perf.data";
 static char            *vmlinux = "vmlinux";
 
 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;
 
@@ -43,6 +40,10 @@ static int           dump_trace = 0;
 
 static int             verbose;
 
+static int             modules;
+
+static int             full_paths;
+
 static int             print_line;
 
 static unsigned long   page_size;
@@ -74,20 +75,12 @@ struct fork_event {
        u32 pid, ppid;
 };
 
-struct period_event {
-       struct perf_event_header header;
-       u64 time;
-       u64 id;
-       u64 sample_period;
-};
-
 typedef union event_union {
        struct perf_event_header        header;
        struct ip_event                 ip;
        struct mmap_event               mmap;
        struct comm_event               comm;
        struct fork_event               fork;
-       struct period_event             period;
 } event_t;
 
 
@@ -160,7 +153,7 @@ static void dsos__fprintf(FILE *fp)
 
 static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
 {
-       return dso__find_symbol(kernel_dso, ip);
+       return dso__find_symbol(dso, ip);
 }
 
 static int load_kernel(void)
@@ -171,8 +164,8 @@ static int load_kernel(void)
        if (!kernel_dso)
                return -1;
 
-       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
-       if (err) {
+       err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
+       if (err <= 0) {
                dso__delete(kernel_dso);
                kernel_dso = NULL;
        } else
@@ -203,7 +196,7 @@ static u64 map__map_ip(struct map *map, u64 ip)
        return ip - map->start + map->pgoff;
 }
 
-static u64 vdso__map_ip(struct map *map, u64 ip)
+static u64 vdso__map_ip(struct map *map __used, u64 ip)
 {
        return ip;
 }
@@ -600,7 +593,7 @@ static LIST_HEAD(hist_entry__sort_list);
 
 static int sort_dimension__add(char *tok)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
                struct sort_dimension *sd = &sort_dimensions[i];
@@ -855,7 +848,7 @@ static unsigned long total = 0,
                     total_unknown = 0;
 
 static int
-process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
+process_sample_event(event_t *event, unsigned long offset, unsigned long head)
 {
        char level;
        int show = 0;
@@ -988,6 +981,13 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
                (void *)(long)(event->header.size),
                event->fork.pid, event->fork.ppid);
 
+       /*
+        * A thread clone will have the same PID for both
+        * parent and child.
+        */
+       if (thread == parent)
+               return 0;
+
        if (!thread || !parent || thread__fork(thread, parent)) {
                dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
                return -1;
@@ -997,26 +997,13 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static int
-process_period_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->period.time,
-               event->period.id,
-               event->period.sample_period);
-
-       return 0;
-}
-
 static int
 process_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
-               return process_overflow_event(event, offset, head);
-
        switch (event->header.type) {
+       case PERF_EVENT_SAMPLE:
+               return process_sample_event(event, offset, head);
+
        case PERF_EVENT_MMAP:
                return process_mmap_event(event, offset, head);
 
@@ -1025,9 +1012,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
 
        case PERF_EVENT_FORK:
                return process_fork_event(event, offset, head);
-
-       case PERF_EVENT_PERIOD:
-               return process_period_event(event, offset, head);
        /*
         * We dont process them right now but they are fine:
         */
@@ -1043,24 +1027,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static char *get_color(double percent)
-{
-       char *color = PERF_COLOR_NORMAL;
-
-       /*
-        * We color high-overhead entries in red, mid-overhead
-        * entries in green - and keep the low overhead places
-        * normal:
-        */
-       if (percent >= MIN_RED)
-               color = PERF_COLOR_RED;
-       else {
-               if (percent > MIN_GREEN)
-                       color = PERF_COLOR_GREEN;
-       }
-       return color;
-}
-
 static int
 parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
 {
@@ -1069,7 +1035,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
        static const char *prev_color;
        unsigned int offset;
        size_t line_len;
-       u64 line_ip;
+       s64 line_ip;
        int ret;
        char *c;
 
@@ -1122,7 +1088,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
                } else if (sym->hist_sum)
                        percent = 100.0 * hits / sym->hist_sum;
 
-               color = get_color(percent);
+               color = get_percent_color(percent);
 
                /*
                 * Also color the filename and line if needed, with
@@ -1258,7 +1224,7 @@ static void print_summary(char *filename)
 
                sym_ext = rb_entry(node, struct sym_ext, node);
                percent = sym_ext->percent;
-               color = get_color(percent);
+               color = get_percent_color(percent);
                path = sym_ext->path;
 
                color_fprintf(stdout, color, " %7.2f %s", percent, path);
@@ -1268,19 +1234,25 @@ static void print_summary(char *filename)
 
 static void annotate_sym(struct dso *dso, struct symbol *sym)
 {
-       char *filename = dso->name;
+       char *filename = dso->name, *d_filename;
        u64 start, end, len;
        char command[PATH_MAX*2];
        FILE *file;
 
        if (!filename)
                return;
-       if (dso == kernel_dso)
+       if (sym->module)
+               filename = sym->module->path;
+       else if (dso == kernel_dso)
                filename = vmlinux;
 
        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;
@@ -1291,13 +1263,14 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
        }
 
        printf("\n\n------------------------------------------------\n");
-       printf(" Percent |      Source code & Disassembly of %s\n", filename);
+       printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
        printf("------------------------------------------------\n");
 
        if (verbose >= 2)
                printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name);
 
-       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", (u64)start, (u64)end, filename);
+       sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
+                       (u64)start, (u64)end, filename, filename);
 
        if (verbose >= 3)
                printf("doing: %s\n", command);
@@ -1362,6 +1335,11 @@ static int __cmd_annotate(void)
                exit(-1);
        }
 
+       if (!force && (stat.st_uid != geteuid())) {
+               fprintf(stderr, "file: %s not owned by current user\n", input_name);
+               exit(-1);
+       }
+
        if (!stat.st_size) {
                fprintf(stderr, "zero-sized file, nothing to do!\n");
                exit(0);
@@ -1428,7 +1406,7 @@ more:
 
        head += size;
 
-       if (offset + head < stat.st_size)
+       if (offset + head < (unsigned long)stat.st_size)
                goto more;
 
        rc = EXIT_SUCCESS;
@@ -1467,13 +1445,18 @@ static const struct option options[] = {
                    "input file name"),
        OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
                    "symbol to annotate"),
+       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
        OPT_BOOLEAN('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('m', "modules", &modules,
+                   "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('l', "print-line", &print_line,
                    "print matching source lines (may be slow)"),
+       OPT_BOOLEAN('P', "full-paths", &full_paths,
+                   "Don't shorten the displayed pathnames"),
        OPT_END()
 };
 
@@ -1492,7 +1475,7 @@ static void setup_sorting(void)
        free(str);
 }
 
-int cmd_annotate(int argc, const char **argv, const char *prefix)
+int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 {
        symbol__init();