]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - tools/perf/builtin-top.c
perf top: Teach it to autolocate vmlinux
[mirror_ubuntu-artful-kernel.git] / tools / perf / builtin-top.c
index ddc584b64871019f0eb08dcd447ff511ce639983..83c09c8f28edf9a008335c5c0166a4044a500887 100644 (file)
@@ -94,6 +94,7 @@ struct source_line {
 
 static char                    *sym_filter                     =   NULL;
 struct sym_entry               *sym_filter_entry               =   NULL;
+struct sym_entry               *sym_filter_entry_sched         =   NULL;
 static int                     sym_pcnt_filter                 =      5;
 static int                     sym_counter                     =      0;
 static int                     display_weighted                =     -1;
@@ -667,7 +668,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
        }
 
        if (!found) {
-               fprintf(stderr, "Sorry, %s is not active.\n", sym_filter);
+               fprintf(stderr, "Sorry, %s is not active.\n", buf);
                sleep(1);
                return;
        } else
@@ -695,11 +696,9 @@ static void print_mapped_keys(void)
 
        fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", count_filter);
 
-       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");
-       }
+       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");
 
        if (nr_counters > 1)
                fprintf(stdout, "\t[w]     toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
@@ -725,14 +724,13 @@ static int key_mapped(int c)
                case 'Q':
                case 'K':
                case 'U':
+               case 'F':
+               case 's':
+               case 'S':
                        return 1;
                case 'E':
                case 'w':
                        return nr_counters > 1 ? 1 : 0;
-               case 'F':
-               case 's':
-               case 'S':
-                       return symbol_conf.vmlinux_name ? 1 : 0;
                default:
                        break;
        }
@@ -910,8 +908,12 @@ static int symbol_filter(struct map *map, struct symbol *sym)
        syme = symbol__priv(sym);
        syme->map = map;
        syme->src = NULL;
-       if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
-               sym_filter_entry = syme;
+
+       if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
+               /* schedule initial sym_filter_entry setup */
+               sym_filter_entry_sched = syme;
+               sym_filter = NULL;
+       }
 
        for (i = 0; skip_symbols[i]; i++) {
                if (!strcmp(skip_symbols[i], name)) {
@@ -934,8 +936,11 @@ static void event__process_sample(const event_t *self,
        struct addr_location al;
        u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
+       ++samples;
+
        switch (origin) {
        case PERF_RECORD_MISC_USER:
+               ++userspace_samples;
                if (hide_user_symbols)
                        return;
                break;
@@ -948,8 +953,37 @@ static void event__process_sample(const event_t *self,
        }
 
        if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
-           al.sym == NULL || al.filtered)
+           al.filtered)
+               return;
+
+       if (al.sym == NULL) {
+               /*
+                * As we do lazy loading of symtabs we only will know if the
+                * specified vmlinux file is invalid when we actually have a
+                * hit in kernel space and then try to load it. So if we get
+                * here and there are _no_ symbols in the DSO backing the
+                * kernel map, bail out.
+                *
+                * We may never get here, for instance, if we use -K/
+                * --hide-kernel-symbols, even if the user specifies an
+                * invalid --vmlinux ;-)
+                */
+               if (al.map == session->vmlinux_maps[MAP__FUNCTION] &&
+                   RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
+                       pr_err("The %s file can't be used\n",
+                              symbol_conf.vmlinux_name);
+                       exit(1);
+               }
+
                return;
+       }
+
+       /* let's see, whether we need to install initial sym_filter_entry */
+       if (sym_filter_entry_sched) {
+               sym_filter_entry = sym_filter_entry_sched;
+               sym_filter_entry_sched = NULL;
+               parse_source(sym_filter_entry);
+       }
 
        syme = symbol__priv(al.sym);
        if (!syme->skip) {
@@ -960,9 +994,6 @@ static void event__process_sample(const event_t *self,
                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;
        }
 }
 
@@ -975,6 +1006,10 @@ static int event__process(event_t *event, struct perf_session *session)
        case PERF_RECORD_MMAP:
                event__process_mmap(event, session);
                break;
+       case PERF_RECORD_FORK:
+       case PERF_RECORD_EXIT:
+               event__process_task(event, session);
+               break;
        default:
                break;
        }
@@ -1244,7 +1279,7 @@ static const struct option options[] = {
        OPT_BOOLEAN('i', "inherit", &inherit,
                    "child tasks inherit counters"),
        OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
-                   "symbol to annotate - requires -k option"),
+                   "symbol to annotate"),
        OPT_BOOLEAN('z', "zero", &zero,
                    "zero history across updates"),
        OPT_INTEGER('F', "freq", &freq,
@@ -1280,16 +1315,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 
        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;
+
+       symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
        if (symbol__init() < 0)
                return -1;
 
        if (delay_secs < 1)
                delay_secs = 1;
 
-       parse_source(sym_filter_entry);
-
        /*
         * User specified count overrides default frequency.
         */