]> Pileus Git - ~andy/linux/blobdiff - tools/perf/builtin-report.c
perf probe: Check build-id of vmlinux
[~andy/linux] / tools / perf / builtin-report.c
index f57a23b19f3c38f1eabb0de5b8e5102811b73ce4..40389c0e38c6b72165facd2cf243caea068bfdd6 100644 (file)
 #include "perf.h"
 #include "util/debug.h"
 #include "util/header.h"
+#include "util/session.h"
 
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
-#include "util/data_map.h"
 #include "util/thread.h"
 #include "util/sort.h"
 #include "util/hist.h"
@@ -38,8 +38,8 @@ static char           *dso_list_str, *comm_list_str, *sym_list_str,
 static struct strlist  *dso_list, *comm_list, *sym_list;
 
 static int             force;
+static bool            use_callchain;
 
-static int             full_paths;
 static int             show_nr_samples;
 
 static int             show_threads;
@@ -52,22 +52,30 @@ static int          exclude_other = 1;
 
 static char            callchain_default_opt[] = "fractal,0.5";
 
-static char            *cwd;
-static int             cwdlen;
+static struct symbol_conf      symbol_conf;
 
-static struct rb_root  threads;
-static struct thread   *last_match;
 
-static struct perf_header *header;
+static size_t
+callchain__fprintf_left_margin(FILE *fp, int left_margin)
+{
+       int i;
+       int ret;
+
+       ret = fprintf(fp, "            ");
 
-static u64             sample_type;
+       for (i = 0; i < left_margin; i++)
+               ret += fprintf(fp, " ");
 
-static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
+       return ret;
+}
+
+static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
+                                         int left_margin)
 {
        int i;
        size_t ret = 0;
 
-       ret += fprintf(fp, "%s", "                ");
+       ret += callchain__fprintf_left_margin(fp, left_margin);
 
        for (i = 0; i < depth; i++)
                if (depth_mask & (1 << i))
@@ -82,12 +90,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
 static size_t
 ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
                       int depth_mask, int count, u64 total_samples,
-                      int hits)
+                      int hits, int left_margin)
 {
        int i;
        size_t ret = 0;
 
-       ret += fprintf(fp, "%s", "                ");
+       ret += callchain__fprintf_left_margin(fp, left_margin);
        for (i = 0; i < depth; i++) {
                if (depth_mask & (1 << i))
                        ret += fprintf(fp, "|");
@@ -125,8 +133,9 @@ static void init_rem_hits(void)
 }
 
 static size_t
-callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
-                       u64 total_samples, int depth, int depth_mask)
+__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+                          u64 total_samples, int depth, int depth_mask,
+                          int left_margin)
 {
        struct rb_node *node, *next;
        struct callchain_node *child;
@@ -167,7 +176,8 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                 * But we keep the older depth mask for the line seperator
                 * to keep the level link until we reach the last child
                 */
-               ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
+               ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
+                                                  left_margin);
                i = 0;
                list_for_each_entry(chain, &child->val, list) {
                        if (chain->ip >= PERF_CONTEXT_MAX)
@@ -175,11 +185,13 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                        ret += ipchain__fprintf_graph(fp, chain, depth,
                                                      new_depth_mask, i++,
                                                      new_total,
-                                                     cumul);
+                                                     cumul,
+                                                     left_margin);
                }
-               ret += callchain__fprintf_graph(fp, child, new_total,
-                                               depth + 1,
-                                               new_depth_mask | (1 << depth));
+               ret += __callchain__fprintf_graph(fp, child, new_total,
+                                                 depth + 1,
+                                                 new_depth_mask | (1 << depth),
+                                                 left_margin);
                node = next;
        }
 
@@ -193,12 +205,51 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
 
                ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
                                              new_depth_mask, 0, new_total,
-                                             remaining);
+                                             remaining, left_margin);
        }
 
        return ret;
 }
 
+
+static size_t
+callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
+                        u64 total_samples, int left_margin)
+{
+       struct callchain_list *chain;
+       bool printed = false;
+       int i = 0;
+       int ret = 0;
+
+       list_for_each_entry(chain, &self->val, list) {
+               if (chain->ip >= PERF_CONTEXT_MAX)
+                       continue;
+
+               if (!i++ && sort__first_dimension == SORT_SYM)
+                       continue;
+
+               if (!printed) {
+                       ret += callchain__fprintf_left_margin(fp, left_margin);
+                       ret += fprintf(fp, "|\n");
+                       ret += callchain__fprintf_left_margin(fp, left_margin);
+                       ret += fprintf(fp, "---");
+
+                       left_margin += 3;
+                       printed = true;
+               } else
+                       ret += callchain__fprintf_left_margin(fp, left_margin);
+
+               if (chain->sym)
+                       ret += fprintf(fp, " %s\n", chain->sym->name);
+               else
+                       ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
+       }
+
+       ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
+
+       return ret;
+}
+
 static size_t
 callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
                        u64 total_samples)
@@ -227,7 +278,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
 
 static size_t
 hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
-                             u64 total_samples)
+                             u64 total_samples, int left_margin)
 {
        struct rb_node *rb_node;
        struct callchain_node *chain;
@@ -247,8 +298,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
                        break;
                case CHAIN_GRAPH_ABS: /* Falldown */
                case CHAIN_GRAPH_REL:
-                       ret += callchain__fprintf_graph(fp, chain,
-                                                       total_samples, 1, 1);
+                       ret += callchain__fprintf_graph(fp, chain, total_samples,
+                                                       left_margin);
                case CHAIN_NONE:
                default:
                        break;
@@ -260,8 +311,9 @@ 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)
+static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self,
+                                 struct perf_session *session,
+                                 u64 total_samples)
 {
        struct sort_entry *se;
        size_t ret;
@@ -293,8 +345,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
 
        ret += fprintf(fp, "\n");
 
-       if (callchain)
-               hist_entry_callchain__fprintf(fp, self, total_samples);
+       if (session->use_callchain) {
+               int left_margin = 0;
+
+               if (sort__first_dimension == SORT_COMM) {
+                       se = list_first_entry(&hist_entry__sort_list, typeof(*se),
+                                               list);
+                       left_margin = se->width ? *se->width : 0;
+                       left_margin -= thread__comm_len(self->thread);
+               }
+
+               hist_entry_callchain__fprintf(fp, self, total_samples,
+                                             left_margin);
+       }
 
        return ret;
 }
@@ -342,136 +405,29 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
        return 0;
 }
 
-
-static struct symbol *
-resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
-{
-       struct map *map = mapp ? *mapp : NULL;
-       u64 ip = *ipp;
-
-       if (map)
-               goto got_map;
-
-       if (!thread)
-               return NULL;
-
-       map = thread__find_map(thread, ip);
-       if (map != NULL) {
-               /*
-                * We have to do this here as we may have a dso
-                * with no symbol hit that has a name longer than
-                * the ones with symbols sampled.
-                */
-               if (!sort_dso.elide && !map->dso->slen_calculated)
-                       dso__calc_col_width(map->dso);
-
-               if (mapp)
-                       *mapp = map;
-got_map:
-               ip = map->map_ip(map, 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 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)
-                       return kernel_maps__find_symbol(ip, mapp);
-       }
-       dump_printf(" ...... dso: %s\n",
-                   map ? map->dso->long_name : "<not found>");
-       dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
-       *ipp  = ip;
-
-       return map ? map->dso->find_symbol(map->dso, ip) : NULL;
-}
-
-static int call__match(struct symbol *sym)
-{
-       if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
-               return 1;
-
-       return 0;
-}
-
-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;
-       unsigned int i;
-
-       if (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 symbol *sym = NULL;
-
-               if (ip >= PERF_CONTEXT_MAX) {
-                       context = ip;
-                       continue;
-               }
-
-               switch (context) {
-               case PERF_CONTEXT_HV:
-                       break;
-               case PERF_CONTEXT_KERNEL:
-                       sym = kernel_maps__find_symbol(ip, &map);
-                       break;
-               default:
-                       sym = resolve_symbol(thread, &map, &ip);
-                       break;
-               }
-
-               if (sym) {
-                       if (sort__has_parent && !*parent && call__match(sym))
-                               *parent = sym;
-                       if (!callchain)
-                               break;
-                       syms[i] = sym;
-               }
-       }
-
-       return syms;
-}
-
 /*
  * collect histogram counts
  */
 
-static int
-hist_entry__add(struct thread *thread, struct map *map,
-               struct symbol *sym, u64 ip, struct ip_callchain *chain,
-               char level, u64 count)
+static int perf_session__add_hist_entry(struct perf_session *self,
+                                       struct addr_location *al,
+                                       struct ip_callchain *chain, u64 count)
 {
        struct symbol **syms = NULL, *parent = NULL;
        bool hit;
        struct hist_entry *he;
 
-       if ((sort__has_parent || callchain) && chain)
-               syms = resolve_callchain(thread, map, chain, &parent);
-
-       he = __hist_entry__add(thread, map, sym, parent,
-                              ip, count, level, &hit);
+       if ((sort__has_parent || self->use_callchain) && chain)
+               syms = perf_session__resolve_callchain(self, al->thread,
+                                                      chain, &parent);
+       he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
        if (he == NULL)
                return -ENOMEM;
 
        if (hit)
                he->count += count;
 
-       if (callchain) {
+       if (self->use_callchain) {
                if (!hit)
                        callchain_init(&he->callchain);
                append_chain(&he->callchain, chain, syms);
@@ -481,7 +437,8 @@ hist_entry__add(struct thread *thread, struct map *map,
        return 0;
 }
 
-static size_t output__fprintf(FILE *fp, u64 total_samples)
+static size_t perf_session__fprintf_hist_entries(struct perf_session *self,
+                                                u64 total_samples, FILE *fp)
 {
        struct hist_entry *pos;
        struct sort_entry *se;
@@ -553,9 +510,9 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
        fprintf(fp, "#\n");
 
 print_entries:
-       for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
                pos = rb_entry(nd, struct hist_entry, rb_node);
-               ret += hist_entry__fprintf(fp, pos, total_samples);
+               ret += hist_entry__fprintf(fp, pos, self, total_samples);
        }
 
        if (sort_order == default_sort_order &&
@@ -588,206 +545,104 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
        return 0;
 }
 
-static int
-process_sample_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_sample_event(event_t *event, struct perf_session *session)
 {
-       char level;
-       struct symbol *sym = NULL;
-       struct thread *thread;
-       u64 ip = event->ip.ip;
-       u64 period = 1;
-       struct map *map = NULL;
-       void *more_data = event->ip.__more_data;
-       struct ip_callchain *chain = NULL;
+       struct sample_data data;
        int cpumode;
+       struct addr_location al;
+       struct thread *thread;
 
-       thread = threads__findnew(event->ip.pid, &threads, &last_match);
+       memset(&data, 0, sizeof(data));
+       data.period = 1;
 
-       if (sample_type & PERF_SAMPLE_PERIOD) {
-               period = *(u64 *)more_data;
-               more_data += sizeof(u64);
-       }
+       event__parse_sample(event, session->sample_type, &data);
 
-       dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
+       dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
                event->header.misc,
-               event->ip.pid, event->ip.tid,
-               (void *)(long)ip,
-               (long long)period);
+               data.pid, data.tid,
+               (void *)(long)data.ip,
+               (long long)data.period);
 
-       if (sample_type & PERF_SAMPLE_CALLCHAIN) {
+       if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
                unsigned int i;
 
-               chain = (void *)more_data;
+               dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
 
-               dump_printf("... chain: nr:%Lu\n", chain->nr);
-
-               if (validate_chain(chain, event) < 0) {
-                       eprintf("call-chain problem with event, skipping it.\n");
+               if (validate_chain(data.callchain, event) < 0) {
+                       pr_debug("call-chain problem with event, "
+                                "skipping it.\n");
                        return 0;
                }
 
                if (dump_trace) {
-                       for (i = 0; i < chain->nr; i++)
-                               dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
+                       for (i = 0; i < data.callchain->nr; i++)
+                               dump_printf("..... %2d: %016Lx\n",
+                                           i, data.callchain->ips[i]);
                }
        }
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
-
+       thread = perf_session__findnew(session, data.pid);
        if (thread == NULL) {
-               eprintf("problem processing %d event, skipping it.\n",
+               pr_debug("problem processing %d event, skipping it.\n",
                        event->header.type);
                return -1;
        }
 
+       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+
        if (comm_list && !strlist__has_entry(comm_list, thread->comm))
                return 0;
 
        cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-       if (cpumode == PERF_RECORD_MISC_KERNEL) {
-               level = 'k';
-               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) {
-               level = '.';
-               sym = resolve_symbol(thread, &map, &ip);
-
-       } else {
-               level = 'H';
-               dump_printf(" ...... dso: [hypervisor]\n");
-       }
+       thread__find_addr_location(thread, session, cpumode,
+                                  MAP__FUNCTION, data.ip, &al, NULL);
+       /*
+        * We have to do this here as we may have a dso with no symbol hit that
+        * has a name longer than the ones with symbols sampled.
+        */
+       if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
+               dso__calc_col_width(al.map->dso);
 
        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)))))
+           (!al.map || !al.map->dso ||
+            !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
+              (al.map->dso->short_name != al.map->dso->long_name &&
+               strlist__has_entry(dso_list, al.map->dso->long_name)))))
                return 0;
 
-       if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
+       if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
                return 0;
 
-       if (hist_entry__add(thread, map, sym, ip,
-                           chain, level, period)) {
-               eprintf("problem incrementing symbol count, skipping event\n");
+       if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
+               pr_debug("problem incrementing symbol count, skipping event\n");
                return -1;
        }
 
-       total += period;
-
-       return 0;
-}
-
-static int
-process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-       struct map *map = map__new(&event->mmap, cwd, cwdlen);
-
-       thread = threads__findnew(event->mmap.pid, &threads, &last_match);
-
-       dump_printf("%p [%p]: PERF_RECORD_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,
-               event->mmap.filename);
-
-       if (thread == NULL || map == NULL) {
-               dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
-               return 0;
-       }
-
-       thread__insert_map(thread, map);
-       total_mmap++;
-
+       session->events_stats.total += data.period;
        return 0;
 }
 
-static int
-process_comm_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_comm_event(event_t *event, struct perf_session *session)
 {
-       struct thread *thread;
-
-       thread = threads__findnew(event->comm.pid, &threads, &last_match);
+       struct thread *thread = perf_session__findnew(session, event->comm.pid);
 
-       dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->comm.comm, event->comm.pid);
+       dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
 
        if (thread == NULL ||
            thread__set_comm_adjust(thread, event->comm.comm)) {
                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
                return -1;
        }
-       total_comm++;
-
-       return 0;
-}
-
-static int
-process_task_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       struct thread *thread;
-       struct thread *parent;
-
-       thread = threads__findnew(event->fork.pid, &threads, &last_match);
-       parent = threads__findnew(event->fork.ppid, &threads, &last_match);
-
-       dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
-               event->fork.pid, event->fork.tid,
-               event->fork.ppid, event->fork.ptid);
-
-       /*
-        * A thread clone will have the same PID for both
-        * parent and child.
-        */
-       if (thread == parent)
-               return 0;
-
-       if (event->header.type == PERF_RECORD_EXIT)
-               return 0;
-
-       if (!thread || !parent || thread__fork(thread, parent)) {
-               dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
-               return -1;
-       }
-       total_fork++;
-
-       return 0;
-}
-
-static int
-process_lost_event(event_t *event, unsigned long offset, unsigned long head)
-{
-       dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
-               (void *)(offset + head),
-               (void *)(long)(event->header.size),
-               event->lost.id,
-               event->lost.lost);
-
-       total_lost += event->lost.lost;
 
        return 0;
 }
 
-static int
-process_read_event(event_t *event, unsigned long offset, unsigned long head)
+static int process_read_event(event_t *event, struct perf_session *session __used)
 {
        struct perf_event_attr *attr;
 
-       attr = perf_header__find_attr(event->read.id, header);
+       attr = perf_header__find_attr(event->read.id, &session->header);
 
        if (show_threads) {
                const char *name = attr ? __event_name(attr->type, attr->config)
@@ -799,37 +654,30 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
                                           event->read.value);
        }
 
-       dump_printf("%p [%p]: PERF_RECORD_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);
+       dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
+                   attr ? __event_name(attr->type, attr->config) : "FAIL",
+                   event->read.value);
 
        return 0;
 }
 
-static int sample_type_check(u64 type)
+static int sample_type_check(struct perf_session *session)
 {
-       sample_type = type;
-
-       if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
+       if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        fprintf(stderr, "selected --sort parent, but no"
                                        " callchain data. Did you call"
                                        " perf record without -g?\n");
                        return -1;
                }
-               if (callchain) {
+               if (session->use_callchain) {
                        fprintf(stderr, "selected -g but no callchain data."
                                        " Did you call perf record without"
                                        " -g?\n");
                        return -1;
                }
-       } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
-                       callchain = 1;
+       } else if (callchain_param.mode != CHAIN_NONE && !session->use_callchain) {
+                       session->use_callchain = true;
                        if (register_callchain_param(&callchain_param) < 0) {
                                fprintf(stderr, "Can't register callchain"
                                                " params\n");
@@ -840,13 +688,13 @@ static int sample_type_check(u64 type)
        return 0;
 }
 
-static struct perf_file_handler file_handler = {
+static struct perf_event_ops event_ops = {
        .process_sample_event   = process_sample_event,
-       .process_mmap_event     = process_mmap_event,
+       .process_mmap_event     = event__process_mmap,
        .process_comm_event     = process_comm_event,
-       .process_exit_event     = process_task_event,
-       .process_fork_event     = process_task_event,
-       .process_lost_event     = process_lost_event,
+       .process_exit_event     = event__process_task,
+       .process_fork_event     = event__process_task,
+       .process_lost_event     = event__process_lost,
        .process_read_event     = process_read_event,
        .sample_type_check      = sample_type_check,
 };
@@ -854,45 +702,41 @@ static struct perf_file_handler file_handler = {
 
 static int __cmd_report(void)
 {
-       struct thread *idle;
        int ret;
+       struct perf_session *session;
 
-       idle = register_idle_thread(&threads, &last_match);
-       thread__comm_adjust(idle);
+       session = perf_session__new(input_name, O_RDONLY, force, &symbol_conf);
+       if (session == NULL)
+               return -ENOMEM;
+
+       session->use_callchain = use_callchain;
 
        if (show_threads)
                perf_read_values_init(&show_threads_values);
 
-       register_perf_file_handler(&file_handler);
-
-       ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
-                                     &cwdlen, &cwd);
+       ret = perf_session__process_events(session, &event_ops);
        if (ret)
-               return ret;
-
-       dump_printf("      IP events: %10ld\n", total);
-       dump_printf("    mmap events: %10ld\n", total_mmap);
-       dump_printf("    comm events: %10ld\n", total_comm);
-       dump_printf("    fork events: %10ld\n", total_fork);
-       dump_printf("    lost events: %10ld\n", total_lost);
-       dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
+               goto out_delete;
 
-       if (dump_trace)
-               return 0;
+       if (dump_trace) {
+               event__print_totals();
+               goto out_delete;
+       }
 
        if (verbose > 3)
-               threads__fprintf(stdout, &threads);
+               perf_session__fprintf(session, stdout);
 
        if (verbose > 2)
                dsos__fprintf(stdout);
 
-       collapse__resort();
-       output__resort(total);
-       output__fprintf(stdout, total);
+       perf_session__collapse_resort(session);
+       perf_session__output_resort(session, session->events_stats.total);
+       perf_session__fprintf_hist_entries(session, session->events_stats.total, stdout);
 
        if (show_threads)
                perf_read_values_destroy(&show_threads_values);
-
+out_delete:
+       perf_session__delete(session);
        return ret;
 }
 
@@ -903,7 +747,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
        char *tok;
        char *endptr;
 
-       callchain = 1;
+       use_callchain = true;
 
        if (!arg)
                return 0;
@@ -924,7 +768,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
 
        else if (!strncmp(tok, "none", strlen(arg))) {
                callchain_param.mode = CHAIN_NONE;
-               callchain = 0;
+               use_callchain = true;
 
                return 0;
        }
@@ -962,9 +806,10 @@ static const struct option options[] = {
                    "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_name, "file", "vmlinux pathname"),
+       OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
        OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
-       OPT_BOOLEAN('m', "modules", &modules,
+       OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
                    "Show a column with the number of samples"),
@@ -974,7 +819,7 @@ static const struct option options[] = {
                   "pretty printing style key: normal raw"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
-       OPT_BOOLEAN('P', "full-paths", &full_paths,
+       OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
                    "Don't shorten the pathnames taking into account the cwd"),
        OPT_STRING('p', "parent", &parent_pattern, "regex",
                   "regex filter to identify parent, see: '--sort parent'"),
@@ -998,21 +843,6 @@ static const struct option options[] = {
        OPT_END()
 };
 
-static void setup_sorting(void)
-{
-       char *tmp, *tok, *str = strdup(sort_order);
-
-       for (tok = strtok_r(str, ", ", &tmp);
-                       tok; tok = strtok_r(NULL, ", ", &tmp)) {
-               if (sort_dimension__add(tok) < 0) {
-                       error("Unknown --sort key: `%s'", tok);
-                       usage_with_options(report_usage, options);
-               }
-       }
-
-       free(str);
-}
-
 static void setup_list(struct strlist **list, const char *list_str,
                       struct sort_entry *se, const char *list_name,
                       FILE *fp)
@@ -1034,11 +864,12 @@ static void setup_list(struct strlist **list, const char *list_str,
 
 int cmd_report(int argc, const char **argv, const char *prefix __used)
 {
-       symbol__init();
+       if (symbol__init(&symbol_conf) < 0)
+               return -1;
 
        argc = parse_options(argc, argv, options, report_usage, 0);
 
-       setup_sorting();
+       setup_sorting(report_usage, options);
 
        if (parent_pattern != default_parent_pattern) {
                sort_dimension__add("parent");