nommu: struct vm_region's vm_usage count need not be atomic
[safe/jmp/linux-2.6] / tools / perf / builtin-top.c
index 6a5de90..ddc584b 100644 (file)
@@ -20,8 +20,9 @@
 
 #include "perf.h"
 
-#include "util/symbol.h"
 #include "util/color.h"
+#include "util/session.h"
+#include "util/symbol.h"
 #include "util/thread.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
@@ -79,7 +80,6 @@ static int                    dump_symtab                     =      0;
 static bool                    hide_kernel_symbols             =  false;
 static bool                    hide_user_symbols               =  false;
 static struct winsize          winsize;
-const char                     *vmlinux_name;
 
 /*
  * Source
@@ -128,7 +128,7 @@ struct sym_entry {
 
 static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
 {
-       return ((void *)self) + symbol__priv_size;
+       return ((void *)self) + symbol_conf.priv_size;
 }
 
 static void get_term_dimensions(struct winsize *ws)
@@ -181,7 +181,7 @@ static void parse_source(struct sym_entry *syme)
                return;
 
        if (syme->src == NULL) {
-               syme->src = calloc(1, sizeof(*source));
+               syme->src = zalloc(sizeof(*source));
                if (syme->src == NULL)
                        return;
                pthread_mutex_init(&syme->src->lock, NULL);
@@ -451,9 +451,8 @@ static void print_sym_table(void)
        struct sym_entry *syme, *n;
        struct rb_root tmp = RB_ROOT;
        struct rb_node *nd;
-       int sym_width = 0, dso_width = 0;
+       int sym_width = 0, dso_width = 0, max_dso_width;
        const int win_width = winsize.ws_col - 1;
-       struct dso *unique_dso = NULL, *first_dso = NULL;
 
        samples = userspace_samples = 0;
 
@@ -539,11 +538,6 @@ static void print_sym_table(void)
                    (int)syme->snap_count < count_filter)
                        continue;
 
-               if (first_dso == NULL)
-                       unique_dso = first_dso = syme->map->dso;
-               else if (syme->map->dso != first_dso)
-                       unique_dso = NULL;
-
                if (syme->map->dso->long_name_len > dso_width)
                        dso_width = syme->map->dso->long_name_len;
 
@@ -553,14 +547,10 @@ static void print_sym_table(void)
 
        printed = 0;
 
-       if (unique_dso)
-               printf("DSO: %s\n", unique_dso->long_name);
-       else {
-               int max_dso_width = winsize.ws_col - sym_width - 29;
-               if (dso_width > max_dso_width)
-                       dso_width = max_dso_width;
-               putchar('\n');
-       }
+       max_dso_width = winsize.ws_col - sym_width - 29;
+       if (dso_width > max_dso_width)
+               dso_width = max_dso_width;
+       putchar('\n');
        if (nr_counters == 1)
                printf("             samples  pcnt");
        else
@@ -568,17 +558,13 @@ static void print_sym_table(void)
 
        if (verbose)
                printf("         RIP       ");
-       printf(" %-*.*s", sym_width, sym_width, "function");
-       if (!unique_dso)
-               printf(" DSO");
-       putchar('\n');
+       printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
        printf("   %s    _______ _____",
               nr_counters == 1 ? "      " : "______");
        if (verbose)
                printf(" ________________");
        printf(" %-*.*s", sym_width, sym_width, graph_line);
-       if (!unique_dso)
-               printf(" %-*.*s", dso_width, dso_width, graph_line);
+       printf(" %-*.*s", dso_width, dso_width, graph_line);
        puts("\n");
 
        for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
@@ -603,12 +589,10 @@ static void print_sym_table(void)
                if (verbose)
                        printf(" %016llx", sym->start);
                printf(" %-*.*s", sym_width, sym_width, sym->name);
-               if (!unique_dso)
-                       printf(" %-*.*s", dso_width, dso_width,
-                              dso_width >= syme->map->dso->long_name_len ?
-                                               syme->map->dso->long_name :
-                                               syme->map->dso->short_name);
-               printf("\n");
+               printf(" %-*.*s\n", dso_width, dso_width,
+                      dso_width >= syme->map->dso->long_name_len ?
+                                       syme->map->dso->long_name :
+                                       syme->map->dso->short_name);
        }
 }
 
@@ -711,7 +695,7 @@ static void print_mapped_keys(void)
 
        fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", count_filter);
 
-       if (vmlinux_name) {
+       if (symbol_conf.vmlinux_name) {
                fprintf(stdout, "\t[F]     annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
                fprintf(stdout, "\t[s]     annotate symbol.                   \t(%s)\n", name?: "NULL");
                fprintf(stdout, "\t[S]     stop annotation.\n");
@@ -748,7 +732,7 @@ static int key_mapped(int c)
                case 'F':
                case 's':
                case 'S':
-                       return vmlinux_name ? 1 : 0;
+                       return symbol_conf.vmlinux_name ? 1 : 0;
                default:
                        break;
        }
@@ -942,58 +926,32 @@ static int symbol_filter(struct map *map, struct symbol *sym)
        return 0;
 }
 
-static void event__process_sample(const event_t *self, int counter)
+static void event__process_sample(const event_t *self,
+                                struct perf_session *session, int counter)
 {
        u64 ip = self->ip.ip;
-       struct map *map;
        struct sym_entry *syme;
-       struct symbol *sym;
+       struct addr_location al;
        u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
        switch (origin) {
-       case PERF_RECORD_MISC_USER: {
-               struct thread *thread;
-
+       case PERF_RECORD_MISC_USER:
                if (hide_user_symbols)
                        return;
-
-               thread = threads__findnew(self->ip.pid);
-               if (thread == NULL)
-                       return;
-
-               map = thread__find_map(thread, ip);
-               if (map != NULL) {
-                       ip = map->map_ip(map, ip);
-                       sym = map__find_symbol(map, ip, symbol_filter);
-                       if (sym == NULL)
-                               return;
-                       userspace_samples++;
-                       break;
-               }
-       }
-               /*
-                * 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).
-                */
-               if ((long long)ip >= 0)
-                       return;
-               /* Fall thru */
+               break;
        case PERF_RECORD_MISC_KERNEL:
                if (hide_kernel_symbols)
                        return;
-
-               sym = kernel_maps__find_symbol(ip, &map, symbol_filter);
-               if (sym == NULL)
-                       return;
                break;
        default:
                return;
        }
 
-       syme = symbol__priv(sym);
+       if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
+           al.sym == NULL || al.filtered)
+               return;
 
+       syme = symbol__priv(al.sym);
        if (!syme->skip) {
                syme->count[counter]++;
                syme->origin = origin;
@@ -1002,38 +960,20 @@ static void event__process_sample(const event_t *self, int counter)
                if (list_empty(&syme->node) || !syme->node.next)
                        __list_insert_active_sym(syme);
                pthread_mutex_unlock(&active_symbols_lock);
+               if (origin == PERF_RECORD_MISC_USER)
+                       ++userspace_samples;
                ++samples;
-               return;
        }
 }
 
-static void event__process_mmap(event_t *self)
-{
-       struct thread *thread = threads__findnew(self->mmap.pid);
-
-       if (thread != NULL) {
-               struct map *map = map__new(&self->mmap, NULL, 0);
-               if (map != NULL)
-                       thread__insert_map(thread, map);
-       }
-}
-
-static void event__process_comm(event_t *self)
-{
-       struct thread *thread = threads__findnew(self->comm.pid);
-
-       if (thread != NULL)
-               thread__set_comm(thread, self->comm.comm);
-}
-
-static int event__process(event_t *event)
+static int event__process(event_t *event, struct perf_session *session)
 {
        switch (event->header.type) {
        case PERF_RECORD_COMM:
-               event__process_comm(event);
+               event__process_comm(event, session);
                break;
        case PERF_RECORD_MMAP:
-               event__process_mmap(event);
+               event__process_mmap(event, session);
                break;
        default:
                break;
@@ -1060,7 +1000,8 @@ static unsigned int mmap_read_head(struct mmap_data *md)
        return head;
 }
 
-static void mmap_read_counter(struct mmap_data *md)
+static void perf_session__mmap_read_counter(struct perf_session *self,
+                                           struct mmap_data *md)
 {
        unsigned int head = mmap_read_head(md);
        unsigned int old = md->prev;
@@ -1113,9 +1054,9 @@ static void mmap_read_counter(struct mmap_data *md)
                }
 
                if (event->header.type == PERF_RECORD_SAMPLE)
-                       event__process_sample(event, md->counter);
+                       event__process_sample(event, self, md->counter);
                else
-                       event__process(event);
+                       event__process(event, self);
                old += size;
        }
 
@@ -1125,13 +1066,13 @@ static void mmap_read_counter(struct mmap_data *md)
 static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
 static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
 
-static void mmap_read(void)
+static void perf_session__mmap_read(struct perf_session *self)
 {
        int i, counter;
 
        for (i = 0; i < nr_cpus; i++) {
                for (counter = 0; counter < nr_counters; counter++)
-                       mmap_read_counter(&mmap_array[i][counter]);
+                       perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
        }
 }
 
@@ -1216,11 +1157,18 @@ static int __cmd_top(void)
        pthread_t thread;
        int i, counter;
        int ret;
+       /*
+        * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
+        * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
+        */
+       struct perf_session *session = perf_session__new(NULL, O_WRONLY, false);
+       if (session == NULL)
+               return -ENOMEM;
 
        if (target_pid != -1)
-               event__synthesize_thread(target_pid, event__process);
+               event__synthesize_thread(target_pid, event__process, session);
        else
-               event__synthesize_threads(event__process);
+               event__synthesize_threads(event__process, session);
 
        for (i = 0; i < nr_cpus; i++) {
                group_fd = -1;
@@ -1231,7 +1179,7 @@ static int __cmd_top(void)
        /* Wait for a minimal set of events before starting the snapshot */
        poll(event_array, nr_poll, 100);
 
-       mmap_read();
+       perf_session__mmap_read(session);
 
        if (pthread_create(&thread, NULL, display_thread, NULL)) {
                printf("Could not create display thread.\n");
@@ -1251,7 +1199,7 @@ static int __cmd_top(void)
        while (1) {
                int hits = samples;
 
-               mmap_read();
+               perf_session__mmap_read(session);
 
                if (hits == samples)
                        ret = poll(event_array, nr_poll, 100);
@@ -1277,7 +1225,8 @@ static const struct option options[] = {
                            "system-wide collection from all CPUs"),
        OPT_INTEGER('C', "CPU", &profile_cpu,
                    "CPU to profile on"),
-       OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
+       OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+                  "file", "vmlinux pathname"),
        OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
                    "hide kernel symbols"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
@@ -1311,7 +1260,7 @@ static const struct option options[] = {
 
 int cmd_top(int argc, const char **argv, const char *prefix __used)
 {
-       int counter, err;
+       int counter;
 
        page_size = sysconf(_SC_PAGE_SIZE);
 
@@ -1329,15 +1278,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        if (!nr_counters)
                nr_counters = 1;
 
-       symbol__init(sizeof(struct sym_entry) +
-                    (nr_counters + 1) * sizeof(unsigned long));
+       symbol_conf.priv_size = (sizeof(struct sym_entry) +
+                                (nr_counters + 1) * sizeof(unsigned long));
+       if (symbol_conf.vmlinux_name == NULL)
+               symbol_conf.try_vmlinux_path = true;
+       if (symbol__init() < 0)
+               return -1;
 
        if (delay_secs < 1)
                delay_secs = 1;
 
-       err = kernel_maps__init(vmlinux_name, !vmlinux_name, true);
-       if (err < 0)
-               return err;
        parse_source(sym_filter_entry);
 
        /*