Merge branch 'irq-threaded-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / tools / perf / builtin-report.c
index 8cb58d6..8b2ec88 100644 (file)
@@ -38,6 +38,7 @@ static char           *dso_list_str, *comm_list_str, *sym_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;
 
@@ -68,7 +69,7 @@ static int            callchain;
 
 static
 struct callchain_param callchain_param = {
-       .mode   = CHAIN_GRAPH_ABS,
+       .mode   = CHAIN_GRAPH_REL,
        .min_percent = 0.5
 };
 
@@ -112,7 +113,9 @@ struct read_event {
        struct perf_event_header header;
        u32 pid,tid;
        u64 value;
-       u64 format[3];
+       u64 time_enabled;
+       u64 time_running;
+       u64 id;
 };
 
 typedef union event_union {
@@ -698,7 +701,8 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
        size_t ret = 0;
 
        if (verbose)
-               ret += repsep_fprintf(fp, "%#018llx  ", (u64)self->ip);
+               ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
+                                     dso__symtab_origin(self->dso));
 
        ret += repsep_fprintf(fp, "[%c] ", self->level);
        if (self->sym) {
@@ -888,6 +892,21 @@ ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
        return ret;
 }
 
+static struct symbol *rem_sq_bracket;
+static struct callchain_list rem_hits;
+
+static void init_rem_hits(void)
+{
+       rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
+       if (!rem_sq_bracket) {
+               fprintf(stderr, "Not enough memory to display remaining hits\n");
+               return;
+       }
+
+       strcpy(rem_sq_bracket->name, "[...]");
+       rem_hits.sym = rem_sq_bracket;
+}
+
 static size_t
 callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                        u64 total_samples, int depth, int depth_mask)
@@ -897,25 +916,34 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
        struct callchain_list *chain;
        int new_depth_mask = depth_mask;
        u64 new_total;
+       u64 remaining;
        size_t ret = 0;
        int i;
 
        if (callchain_param.mode == CHAIN_GRAPH_REL)
-               new_total = self->cumul_hit;
+               new_total = self->children_hit;
        else
                new_total = total_samples;
 
+       remaining = new_total;
+
        node = rb_first(&self->rb_root);
        while (node) {
+               u64 cumul;
+
                child = rb_entry(node, struct callchain_node, rb_node);
+               cumul = cumul_hits(child);
+               remaining -= cumul;
 
                /*
                 * The depth mask manages the output of pipes that show
                 * the depth. We don't want to keep the pipes of the current
-                * level for the last child of this depth
+                * level for the last child of this depth.
+                * Except if we have remaining filtered hits. They will
+                * supersede the last child
                 */
                next = rb_next(node);
-               if (!next)
+               if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
                        new_depth_mask &= ~(1 << (depth - 1));
 
                /*
@@ -930,7 +958,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                        ret += ipchain__fprintf_graph(fp, chain, depth,
                                                      new_depth_mask, i++,
                                                      new_total,
-                                                     child->cumul_hit);
+                                                     cumul);
                }
                ret += callchain__fprintf_graph(fp, child, new_total,
                                                depth + 1,
@@ -938,6 +966,19 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                node = next;
        }
 
+       if (callchain_param.mode == CHAIN_GRAPH_REL &&
+               remaining && remaining != new_total) {
+
+               if (!rem_sq_bracket)
+                       return ret;
+
+               new_depth_mask &= ~(1 << (depth - 1));
+
+               ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
+                                             new_depth_mask, 0, new_total,
+                                             remaining);
+       }
+
        return ret;
 }
 
@@ -1358,6 +1399,8 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
        unsigned int width;
        char *col_width = col_width_list_str;
 
+       init_rem_hits();
+
        fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
        fprintf(fp, "#\n");
 
@@ -1429,6 +1472,8 @@ print_entries:
        }
        fprintf(fp, "\n");
 
+       free(rem_sq_bracket);
+
        return ret;
 }
 
@@ -1482,11 +1527,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
                more_data += sizeof(u64);
        }
 
-       dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
+       dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->header.misc,
-               event->ip.pid,
+               event->ip.pid, event->ip.tid,
                (void *)(long)ip,
                (long long)period);
 
@@ -1546,10 +1591,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
        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))
+               if (dso_list && (!dso || !dso->name ||
+                                !strlist__has_entry(dso_list, dso->name)))
                        return 0;
 
-               if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+               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)) {
@@ -1568,10 +1614,11 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
        struct thread *thread = threads__findnew(event->mmap.pid);
        struct map *map = map__new(&event->mmap);
 
-       dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
+       dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
                (void *)(offset + head),
                (void *)(long)(event->header.size),
                event->mmap.pid,
+               event->mmap.tid,
                (void *)(long)event->mmap.start,
                (void *)(long)event->mmap.len,
                (void *)(long)event->mmap.pgoff,
@@ -1690,14 +1737,37 @@ static void trace_event(event_t *event)
        dprintf(".\n");
 }
 
+static struct perf_header      *header;
+
+static struct perf_counter_attr *perf_header__find_attr(u64 id)
+{
+       int i;
+
+       for (i = 0; i < header->attrs; i++) {
+               struct perf_header_attr *attr = header->attr[i];
+               int j;
+
+               for (j = 0; j < attr->ids; j++) {
+                       if (attr->id[j] == id)
+                               return &attr->attr;
+               }
+       }
+
+       return NULL;
+}
+
 static int
 process_read_event(event_t *event, unsigned long offset, unsigned long head)
 {
-       dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n",
+       struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
+
+       dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
                        (void *)(offset + head),
                        (void *)(long)(event->header.size),
                        event->read.pid,
                        event->read.tid,
+                       attr ? __event_name(attr->type, attr->config)
+                            : "FAIL",
                        event->read.value);
 
        return 0;
@@ -1743,8 +1813,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
        return 0;
 }
 
-static struct perf_header      *header;
-
 static u64 perf_header__sample_type(void)
 {
        u64 sample_type = 0;
@@ -1789,6 +1857,11 @@ static int __cmd_report(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);
@@ -1812,6 +1885,13 @@ static int __cmd_report(void)
                                        " -g?\n");
                        exit(-1);
                }
+       } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
+                       callchain = 1;
+                       if (register_callchain_param(&callchain_param) < 0) {
+                               fprintf(stderr, "Can't register callchain"
+                                               " params\n");
+                               exit(-1);
+                       }
        }
 
        if (load_kernel() < 0) {
@@ -1950,6 +2030,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
        else if (!strncmp(tok, "fractal", strlen(arg)))
                callchain_param.mode = CHAIN_GRAPH_REL;
 
+       else if (!strncmp(tok, "none", strlen(arg))) {
+               callchain_param.mode = CHAIN_NONE;
+               callchain = 0;
+
+               return 0;
+       }
+
        else
                return -1;
 
@@ -1983,6 +2070,7 @@ static const struct option options[] = {
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
        OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
+       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
        OPT_BOOLEAN('m', "modules", &modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,