diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 135 |
1 files changed, 83 insertions, 52 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 377971dc89a..0aa7747ff13 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -59,7 +59,7 @@ #include <sys/syscall.h> #include <sys/ioctl.h> -#include <sys/poll.h> +#include <poll.h> #include <sys/prctl.h> #include <sys/wait.h> #include <sys/uio.h> @@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top) char bf[160]; int printed = 0; const int win_width = top->winsize.ws_col - 1; + struct hists *hists = evsel__hists(top->sym_evsel); puts(CONSOLE_CLEAR); @@ -261,13 +262,13 @@ static void perf_top__print_sym_table(struct perf_top *top) printf("%-*.*s\n", win_width, win_width, graph_dotted_line); - if (top->sym_evsel->hists.stats.nr_lost_warned != - top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { - top->sym_evsel->hists.stats.nr_lost_warned = - top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + if (hists->stats.nr_lost_warned != + hists->stats.nr_events[PERF_RECORD_LOST]) { + hists->stats.nr_lost_warned = + hists->stats.nr_events[PERF_RECORD_LOST]; color_fprintf(stdout, PERF_COLOR_RED, "WARNING: LOST %d chunks, Check IO/CPU overload", - top->sym_evsel->hists.stats.nr_lost_warned); + hists->stats.nr_lost_warned); ++printed; } @@ -276,16 +277,19 @@ static void perf_top__print_sym_table(struct perf_top *top) return; } - 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); + if (top->zero) { + hists__delete_entries(hists); + } else { + hists__decay_entries(hists, top->hide_user_symbols, + top->hide_kernel_symbols); + } + + hists__collapse_resort(hists, NULL); + hists__output_resort(hists); + + hists__output_recalc_col_len(hists, top->print_entries - printed); putchar('\n'); - hists__fprintf(&top->sym_evsel->hists, false, - top->print_entries - printed, win_width, + hists__fprintf(hists, false, top->print_entries - printed, win_width, top->min_percent, stdout); } @@ -328,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) { char *buf = malloc(0), *p; struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; + struct hists *hists = evsel__hists(top->sym_evsel); struct rb_node *next; size_t dummy = 0; @@ -345,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) if (p) *p = 0; - next = rb_first(&top->sym_evsel->hists.entries); + next = rb_first(&hists->entries); while (next) { n = rb_entry(next, struct hist_entry, rb_node); if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { @@ -427,18 +432,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) if (!perf_top__key_mapped(top, c)) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; - struct termios tc, save; + struct termios save; perf_top__print_mapped_keys(top); fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); fflush(stdout); - tcgetattr(0, &save); - tc = save; - tc.c_lflag &= ~(ICANON | ECHO); - tc.c_cc[VMIN] = 0; - tc.c_cc[VTIME] = 0; - tcsetattr(0, TCSANOW, &tc); + set_term_quiet_input(&save); poll(&stdin_poll, 1, -1); c = getc(stdin); @@ -537,16 +537,24 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) static void perf_top__sort_new_samples(void *arg) { struct perf_top *t = arg; + struct hists *hists; + perf_top__reset_sample_counters(t); if (t->evlist->selected != NULL) t->sym_evsel = t->evlist->selected; - 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); + hists = evsel__hists(t->sym_evsel); + + if (t->zero) { + hists__delete_entries(hists); + } else { + hists__decay_entries(hists, t->hide_user_symbols, + t->hide_kernel_symbols); + } + + hists__collapse_resort(hists, NULL); + hists__output_resort(hists); } static void *display_thread_tui(void *arg) @@ -567,8 +575,10 @@ static void *display_thread_tui(void *arg) * Zooming in/out UIDs. For now juse use whatever the user passed * via --uid. */ - evlist__for_each(top->evlist, pos) - pos->hists.uid_filter_str = top->record_opts.target.uid_str; + evlist__for_each(top->evlist, pos) { + struct hists *hists = evsel__hists(pos); + hists->uid_filter_str = top->record_opts.target.uid_str; + } perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, &top->session->header.env); @@ -577,23 +587,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); @@ -620,13 +639,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. @@ -750,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool, } if (al.sym == NULL || !al.sym->ignore) { + struct hists *hists = evsel__hists(evsel); struct hist_entry_iter iter = { .add_entry_cb = hist_iter__top_callback, }; @@ -759,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool, else iter.ops = &hist_iter_normal; - pthread_mutex_lock(&evsel->hists.lock); + pthread_mutex_lock(&hists->lock); 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"); - pthread_mutex_unlock(&evsel->hists.lock); + pthread_mutex_unlock(&hists->lock); } return; @@ -831,7 +854,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) perf_event__process_sample(&top->tool, event, evsel, &sample, machine); } else if (event->header.type < PERF_RECORD_MAX) { - hists__inc_nr_events(&evsel->hists, event->header.type); + hists__inc_nr_events(evsel__hists(evsel), event->header.type); machine__process_event(machine, event, &sample); } else ++session->stats.nr_unknown_events; @@ -876,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; } @@ -911,7 +934,7 @@ static int __cmd_top(struct perf_top *top) top->session = perf_session__new(NULL, false, NULL); if (top->session == NULL) - return -ENOMEM; + return -1; machines__set_symbol_filter(&top->session->machines, symbol_filter); @@ -946,7 +969,7 @@ static int __cmd_top(struct perf_top *top) perf_evlist__enable(top->evlist); /* Wait for a minimal set of events before starting the snapshot */ - poll(top->evlist->pollfd, top->evlist->nr_fds, 100); + perf_evlist__poll(top->evlist, 100); perf_top__mmap_read(top); @@ -963,7 +986,7 @@ static int __cmd_top(struct perf_top *top) param.sched_priority = top->realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { ui__error("Could not set realtime priority.\n"); - goto out_delete; + goto out_join; } } @@ -973,10 +996,12 @@ static int __cmd_top(struct perf_top *top) perf_top__mmap_read(top); if (hits == top->samples) - ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); + ret = perf_evlist__poll(top->evlist, 100); } ret = 0; +out_join: + pthread_join(thread, NULL); out_delete: perf_session__delete(top->session); top->session = NULL; @@ -1000,10 +1025,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) static int perf_top_config(const char *var, const char *value, void *cb) { - struct perf_top *top = cb; - if (!strcmp(var, "top.call-graph")) - return record_parse_callchain(value, &top->record_opts); + var = "call-graph.record-mode"; /* fall-through */ if (!strcmp(var, "top.children")) { symbol_conf.cumulate_callchain = perf_config_bool(var, value); return 0; @@ -1024,7 +1047,6 @@ parse_percent_limit(const struct option *opt, const char *arg, int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) { - int status = -1; char errbuf[BUFSIZ]; struct perf_top top = { .count_filter = 5, @@ -1122,6 +1144,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "Interleave source code with assembly code (default)"), OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, "Display raw encoding of assembly instructions (default)"), + OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, + "Enable kernel symbol demangling"), OPT_STRING(0, "objdump", &objdump_path, "path", "objdump binary to use for disassembly and annotations"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", @@ -1131,12 +1155,19 @@ 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[] = { "perf top [<options>]", NULL }; + int status = hists__init(); + + if (status < 0) + return status; top.evlist = perf_evlist__new(); if (top.evlist == NULL) @@ -1217,7 +1248,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 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); |