perf symbols: Don't try to find DSOs in SYSV maps
[deliverable/linux.git] / tools / perf / builtin-top.c
index 5b389ce4cd15d03b656185f83d58f10aca94fd81..a77ff6ca5fbd9e9425a03dbfbb73d3dc25507900 100644 (file)
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,
 
        pthread_mutex_unlock(&notes->lock);
 
+       /*
+        * This function is now called with he->hists->lock held.
+        * Release it before going to sleep.
+        */
+       pthread_mutex_unlock(&he->hists->lock);
+
        if (err == -ERANGE && !he->ms.map->erange_warned)
                ui__warn_map_erange(he->ms.map, sym, ip);
        else if (err == -ENOMEM) {
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top,
                       sym->name);
                sleep(1);
        }
+
+       pthread_mutex_lock(&he->hists->lock);
 }
 
 static void perf_top__show_details(struct perf_top *top)
@@ -238,27 +246,6 @@ out_unlock:
        pthread_mutex_unlock(&notes->lock);
 }
 
-static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
-                                                    struct addr_location *al,
-                                                    struct perf_sample *sample)
-{
-       struct hist_entry *he;
-
-       pthread_mutex_lock(&evsel->hists.lock);
-       he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL,
-                               sample->period, sample->weight,
-                               sample->transaction);
-       pthread_mutex_unlock(&evsel->hists.lock);
-       if (he == NULL)
-               return NULL;
-
-       hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
-       if (!he->filtered)
-               evsel->hists.stats.nr_non_filtered_samples++;
-
-       return he;
-}
-
 static void perf_top__print_sym_table(struct perf_top *top)
 {
        char bf[160];
@@ -289,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
                return;
        }
 
+       if (top->zero) {
+               hists__delete_entries(&top->sym_evsel->hists);
+       } else {
+               hists__decay_entries(&top->sym_evsel->hists,
+                                    top->hide_user_symbols,
+                                    top->hide_kernel_symbols);
+       }
+
        hists__collapse_resort(&top->sym_evsel->hists, NULL);
        hists__output_resort(&top->sym_evsel->hists);
-       hists__decay_entries(&top->sym_evsel->hists,
-                            top->hide_user_symbols,
-                            top->hide_kernel_symbols);
+
        hists__output_recalc_col_len(&top->sym_evsel->hists,
                                     top->print_entries - printed);
        putchar('\n');
@@ -555,11 +548,16 @@ static void perf_top__sort_new_samples(void *arg)
        if (t->evlist->selected != NULL)
                t->sym_evsel = t->evlist->selected;
 
+       if (t->zero) {
+               hists__delete_entries(&t->sym_evsel->hists);
+       } else {
+               hists__decay_entries(&t->sym_evsel->hists,
+                                    t->hide_user_symbols,
+                                    t->hide_kernel_symbols);
+       }
+
        hists__collapse_resort(&t->sym_evsel->hists, NULL);
        hists__output_resort(&t->sym_evsel->hists);
-       hists__decay_entries(&t->sym_evsel->hists,
-                            t->hide_user_symbols,
-                            t->hide_kernel_symbols);
 }
 
 static void *display_thread_tui(void *arg)
@@ -590,23 +588,32 @@ static void *display_thread_tui(void *arg)
        return NULL;
 }
 
+static void display_sig(int sig __maybe_unused)
+{
+       done = 1;
+}
+
+static void display_setup_sig(void)
+{
+       signal(SIGSEGV, display_sig);
+       signal(SIGFPE,  display_sig);
+       signal(SIGINT,  display_sig);
+       signal(SIGQUIT, display_sig);
+       signal(SIGTERM, display_sig);
+}
+
 static void *display_thread(void *arg)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
-       struct termios tc, save;
+       struct termios save;
        struct perf_top *top = arg;
        int delay_msecs, c;
 
-       tcgetattr(0, &save);
-       tc = save;
-       tc.c_lflag &= ~(ICANON | ECHO);
-       tc.c_cc[VMIN] = 0;
-       tc.c_cc[VTIME] = 0;
-
+       display_setup_sig();
        pthread__unblock_sigwinch();
 repeat:
        delay_msecs = top->delay_secs * 1000;
-       tcsetattr(0, TCSANOW, &tc);
+       set_term_quiet_input(&save);
        /* trash return*/
        getc(stdin);
 
@@ -633,13 +640,16 @@ repeat:
                }
        }
 
+       tcsetattr(0, TCSAFLUSH, &save);
        return NULL;
 }
 
-static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
+static int symbol_filter(struct map *map, struct symbol *sym)
 {
        const char *name = sym->name;
 
+       if (!map->dso->kernel)
+               return 0;
        /*
         * ppc64 uses function descriptors and appends a '.' to the
         * start of every instruction address. Remove it.
@@ -662,6 +672,26 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
        return 0;
 }
 
+static int hist_iter__top_callback(struct hist_entry_iter *iter,
+                                  struct addr_location *al, bool single,
+                                  void *arg)
+{
+       struct perf_top *top = arg;
+       struct hist_entry *he = iter->he;
+       struct perf_evsel *evsel = iter->evsel;
+
+       if (sort__has_sym && single) {
+               u64 ip = al->addr;
+
+               if (al->map)
+                       ip = al->map->unmap_ip(al->map, ip);
+
+               perf_top__record_precise_ip(top, he, evsel->idx, ip);
+       }
+
+       return 0;
+}
+
 static void perf_event__process_sample(struct perf_tool *tool,
                                       const union perf_event *event,
                                       struct perf_evsel *evsel,
@@ -669,8 +699,6 @@ static void perf_event__process_sample(struct perf_tool *tool,
                                       struct machine *machine)
 {
        struct perf_top *top = container_of(tool, struct perf_top, tool);
-       struct symbol *parent = NULL;
-       u64 ip = sample->ip;
        struct addr_location al;
        int err;
 
@@ -745,25 +773,23 @@ static void perf_event__process_sample(struct perf_tool *tool,
        }
 
        if (al.sym == NULL || !al.sym->ignore) {
-               struct hist_entry *he;
+               struct hist_entry_iter iter = {
+                       .add_entry_cb = hist_iter__top_callback,
+               };
 
-               err = sample__resolve_callchain(sample, &parent, evsel, &al,
-                                               top->max_stack);
-               if (err)
-                       return;
+               if (symbol_conf.cumulate_callchain)
+                       iter.ops = &hist_iter_cumulative;
+               else
+                       iter.ops = &hist_iter_normal;
 
-               he = perf_evsel__add_hist_entry(evsel, &al, sample);
-               if (he == NULL) {
-                       pr_err("Problem incrementing symbol period, skipping event\n");
-                       return;
-               }
+               pthread_mutex_lock(&evsel->hists.lock);
 
-               err = hist_entry__append_callchain(he, sample);
-               if (err)
-                       return;
+               err = hist_entry_iter__add(&iter, &al, evsel, sample,
+                                          top->max_stack, top);
+               if (err < 0)
+                       pr_err("Problem incrementing symbol period, skipping event\n");
 
-               if (sort__has_sym)
-                       perf_top__record_precise_ip(top, he, evsel->idx, ip);
+               pthread_mutex_unlock(&evsel->hists.lock);
        }
 
        return;
@@ -873,7 +899,7 @@ try_again:
 
        if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
                ui__error("Failed to mmap with %d (%s)\n",
-                           errno, strerror(errno));
+                           errno, strerror_r(errno, msg, sizeof(msg)));
                goto out_err;
        }
 
@@ -960,7 +986,7 @@ static int __cmd_top(struct perf_top *top)
                param.sched_priority = top->realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                        ui__error("Could not set realtime priority.\n");
-                       goto out_delete;
+                       goto out_join;
                }
        }
 
@@ -974,6 +1000,8 @@ static int __cmd_top(struct perf_top *top)
        }
 
        ret = 0;
+out_join:
+       pthread_join(thread, NULL);
 out_delete:
        perf_session__delete(top->session);
        top->session = NULL;
@@ -1001,6 +1029,10 @@ static int perf_top_config(const char *var, const char *value, void *cb)
 
        if (!strcmp(var, "top.call-graph"))
                return record_parse_callchain(value, &top->record_opts);
+       if (!strcmp(var, "top.children")) {
+               symbol_conf.cumulate_callchain = perf_config_bool(var, value);
+               return 0;
+       }
 
        return perf_default_config(var, value, cb);
 }
@@ -1095,6 +1127,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_CALLBACK(0, "call-graph", &top.record_opts,
                     "mode[,dump_size]", record_callchain_help,
                     &parse_callchain_opt),
+       OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
+                   "Accumulate callchains of children and show total overhead as well"),
        OPT_INTEGER(0, "max-stack", &top.max_stack,
                    "Set the maximum stack depth when parsing the callchain. "
                    "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
@@ -1122,6 +1156,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Don't show entries under that percent", parse_percent_limit),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
                     "How to display percentage of filtered entries", parse_filter_percentage),
+       OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
+                  "width[,width...]",
+                  "don't try to adjust column width, use these fixed values"),
        OPT_END()
        };
        const char * const top_usage[] = {
@@ -1200,10 +1237,15 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 
        top.sym_evsel = perf_evlist__first(top.evlist);
 
+       if (!symbol_conf.use_callchain) {
+               symbol_conf.cumulate_callchain = false;
+               perf_hpp__cancel_cumulate();
+       }
+
        symbol_conf.priv_size = sizeof(struct annotation);
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
-       if (symbol__init() < 0)
+       if (symbol__init(NULL) < 0)
                return -1;
 
        sort__setup_elide(stdout);
This page took 0.029049 seconds and 5 git commands to generate.