diff options
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r-- | tools/perf/builtin-top.c | 77 |
1 files changed, 57 insertions, 20 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8f80df89603..e3c63aef8ef 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -64,7 +64,6 @@ #include <linux/unistd.h> #include <linux/types.h> - void get_term_dimensions(struct winsize *ws) { char *s = getenv("LINES"); @@ -89,8 +88,6 @@ void get_term_dimensions(struct winsize *ws) static void perf_top__update_print_entries(struct perf_top *top) { - top->print_entries = top->winsize.ws_row; - if (top->print_entries > 9) top->print_entries -= 9; } @@ -100,6 +97,13 @@ static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *ar struct perf_top *top = arg; get_term_dimensions(&top->winsize); + if (!top->print_entries + || (top->print_entries+4) > top->winsize.ws_row) { + top->print_entries = top->winsize.ws_row; + } else { + top->print_entries += 4; + top->winsize.ws_row = top->print_entries; + } perf_top__update_print_entries(top); } @@ -453,8 +457,10 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) }; perf_top__sig_winch(SIGWINCH, NULL, top); sigaction(SIGWINCH, &act, NULL); - } else + } else { + perf_top__sig_winch(SIGWINCH, NULL, top); signal(SIGWINCH, SIG_DFL); + } break; case 'E': if (top->evlist->nr_entries > 1) { @@ -537,10 +543,20 @@ static void perf_top__sort_new_samples(void *arg) static void *display_thread_tui(void *arg) { + struct perf_evsel *pos; struct perf_top *top = arg; const char *help = "For a higher level overview, try: perf top --sort comm,dso"; perf_top__sort_new_samples(top); + + /* + * Initialize the uid_filter_str, in the future the TUI will allow + * Zooming in/out UIDs. For now juse use whatever the user passed + * via --uid. + */ + list_for_each_entry(pos, &top->evlist->entries, node) + pos->hists.uid_filter_str = top->uid_str; + perf_evlist__tui_browse_hists(top->evlist, help, perf_top__sort_new_samples, top, top->delay_secs); @@ -661,6 +677,12 @@ static void perf_event__process_sample(struct perf_tool *tool, return; } + if (!machine) { + pr_err("%u unprocessable samples recorded.", + top->session->hists.stats.nr_unprocessable_samples++); + return; + } + if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) top->exact_samples++; @@ -850,8 +872,11 @@ static void perf_top__start_counters(struct perf_top *top) attr->mmap = 1; attr->comm = 1; attr->inherit = top->inherit; +fallback_missing_features: + if (top->exclude_guest_missing) + attr->exclude_guest = attr->exclude_host = 0; retry_sample_id: - attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; + attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads, top->group, @@ -861,12 +886,20 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; - } else if (err == EINVAL && top->sample_id_all_avail) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - top->sample_id_all_avail = false; - goto retry_sample_id; + } else if (err == EINVAL) { + if (!top->exclude_guest_missing && + (attr->exclude_guest || attr->exclude_host)) { + pr_debug("Old kernel, cannot exclude " + "guest or host samples.\n"); + top->exclude_guest_missing = true; + goto fallback_missing_features; + } else if (!top->sample_id_all_missing) { + /* + * Old kernel, no attr->sample_id_type_all field + */ + top->sample_id_all_missing = true; + goto retry_sample_id; + } } /* * If it's cycles then fall back to hrtimer @@ -949,7 +982,7 @@ static int __cmd_top(struct perf_top *top) if (ret) goto out_delete; - if (top->target_tid != -1) + if (top->target_tid || top->uid != UINT_MAX) perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__process, &top->session->host_machine); @@ -1087,10 +1120,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) struct perf_top top = { .count_filter = 5, .delay_secs = 2, - .target_pid = -1, - .target_tid = -1, + .uid = UINT_MAX, .freq = 1000, /* 1 KHz */ - .sample_id_all_avail = true, .mmap_pages = 128, .sym_pcnt_filter = 5, }; @@ -1101,9 +1132,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) parse_events_option), OPT_INTEGER('c', "count", &top.default_interval, "event period to sample"), - OPT_INTEGER('p', "pid", &top.target_pid, + OPT_STRING('p', "pid", &top.target_pid, "pid", "profile events on existing process id"), - OPT_INTEGER('t', "tid", &top.target_tid, + OPT_STRING('t', "tid", &top.target_tid, "tid", "profile events on existing thread id"), OPT_BOOLEAN('a', "all-cpus", &top.system_wide, "system-wide collection from all CPUs"), @@ -1162,6 +1193,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"), OPT_END() }; @@ -1187,18 +1219,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) setup_browser(false); + top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid); + if (top.uid_str != NULL && top.uid == UINT_MAX - 1) + goto out_delete_evlist; + /* CPU and PID are mutually exclusive */ - if (top.target_tid > 0 && top.cpu_list) { + if (top.target_tid && top.cpu_list) { printf("WARNING: PID switch overriding CPU\n"); sleep(1); top.cpu_list = NULL; } - if (top.target_pid != -1) + if (top.target_pid) top.target_tid = top.target_pid; if (perf_evlist__create_maps(top.evlist, top.target_pid, - top.target_tid, top.cpu_list) < 0) + top.target_tid, top.uid, top.cpu_list) < 0) usage_with_options(top_usage, options); if (!top.evlist->nr_entries && @@ -1262,6 +1298,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) status = __cmd_top(&top); +out_delete_evlist: perf_evlist__delete(top.evlist); return status; |