perf report: Generalize perf_session__fprintf_hists()
[safe/jmp/linux-2.6] / tools / perf / util / session.c
index 09836a5..ce3a6c8 100644 (file)
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 
 #include "session.h"
+#include "sort.h"
 #include "util.h"
 
 static int perf_session__open(struct perf_session *self, bool force)
@@ -48,8 +49,7 @@ out_close:
        return -1;
 }
 
-struct perf_session *perf_session__new(const char *filename, int mode,
-                                      bool force)
+struct perf_session *perf_session__new(const char *filename, int mode, bool force)
 {
        size_t len = filename ? strlen(filename) + 1 : 0;
        struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -58,7 +58,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
                goto out;
 
        if (perf_header__init(&self->header) < 0)
-               goto out_delete;
+               goto out_free;
 
        memcpy(self->filename, filename, len);
        self->threads = RB_ROOT;
@@ -66,16 +66,21 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        self->mmap_window = 32;
        self->cwd = NULL;
        self->cwdlen = 0;
+       map_groups__init(&self->kmaps);
 
-       if (mode == O_RDONLY && perf_session__open(self, force) < 0) {
-               perf_session__delete(self);
-               self = NULL;
-       }
+       if (perf_session__create_kernel_maps(self) < 0)
+               goto out_delete;
+
+       if (mode == O_RDONLY && perf_session__open(self, force) < 0)
+               goto out_delete;
 out:
        return self;
-out_delete:
+out_free:
        free(self);
        return NULL;
+out_delete:
+       perf_session__delete(self);
+       return NULL;
 }
 
 void perf_session__delete(struct perf_session *self)
@@ -85,3 +90,61 @@ void perf_session__delete(struct perf_session *self)
        free(self->cwd);
        free(self);
 }
+
+static bool symbol__match_parent_regex(struct symbol *sym)
+{
+       if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
+               return 1;
+
+       return 0;
+}
+
+struct symbol **perf_session__resolve_callchain(struct perf_session *self,
+                                               struct thread *thread,
+                                               struct ip_callchain *chain,
+                                               struct symbol **parent)
+{
+       u8 cpumode = PERF_RECORD_MISC_USER;
+       struct symbol **syms = NULL;
+       unsigned int i;
+
+       if (symbol_conf.use_callchain) {
+               syms = calloc(chain->nr, sizeof(*syms));
+               if (!syms) {
+                       fprintf(stderr, "Can't allocate memory for symbols\n");
+                       exit(-1);
+               }
+       }
+
+       for (i = 0; i < chain->nr; i++) {
+               u64 ip = chain->ips[i];
+               struct addr_location al;
+
+               if (ip >= PERF_CONTEXT_MAX) {
+                       switch (ip) {
+                       case PERF_CONTEXT_HV:
+                               cpumode = PERF_RECORD_MISC_HYPERVISOR;  break;
+                       case PERF_CONTEXT_KERNEL:
+                               cpumode = PERF_RECORD_MISC_KERNEL;      break;
+                       case PERF_CONTEXT_USER:
+                               cpumode = PERF_RECORD_MISC_USER;        break;
+                       default:
+                               break;
+                       }
+                       continue;
+               }
+
+               thread__find_addr_location(thread, self, cpumode,
+                                          MAP__FUNCTION, ip, &al, NULL);
+               if (al.sym != NULL) {
+                       if (sort__has_parent && !*parent &&
+                           symbol__match_parent_regex(al.sym))
+                               *parent = al.sym;
+                       if (!symbol_conf.use_callchain)
+                               break;
+                       syms[i] = al.sym;
+               }
+       }
+
+       return syms;
+}