diff options
| -rw-r--r-- | tools/perf/builtin-top.c | 92 |
1 files changed, 67 insertions, 25 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 89b7f68a1799..a368978d5177 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -78,6 +78,14 @@ static int dump_symtab = 0; | |||
| 78 | 78 | ||
| 79 | static bool hide_kernel_symbols = false; | 79 | static bool hide_kernel_symbols = false; |
| 80 | static bool hide_user_symbols = false; | 80 | static bool hide_user_symbols = false; |
| 81 | static struct winsize winsize; | ||
| 82 | static const char *graph_line = | ||
| 83 | "_____________________________________________________________________" | ||
| 84 | "_____________________________________________________________________"; | ||
| 85 | static const char *graph_dotted_line = | ||
| 86 | "---------------------------------------------------------------------" | ||
| 87 | "---------------------------------------------------------------------" | ||
| 88 | "---------------------------------------------------------------------"; | ||
| 81 | 89 | ||
| 82 | /* | 90 | /* |
| 83 | * Source | 91 | * Source |
| @@ -107,6 +115,7 @@ struct sym_entry { | |||
| 107 | unsigned long snap_count; | 115 | unsigned long snap_count; |
| 108 | double weight; | 116 | double weight; |
| 109 | int skip; | 117 | int skip; |
| 118 | u16 name_len; | ||
| 110 | u8 origin; | 119 | u8 origin; |
| 111 | struct map *map; | 120 | struct map *map; |
| 112 | struct source_line *source; | 121 | struct source_line *source; |
| @@ -119,34 +128,40 @@ struct sym_entry { | |||
| 119 | * Source functions | 128 | * Source functions |
| 120 | */ | 129 | */ |
| 121 | 130 | ||
| 122 | /* most GUI terminals set LINES (although some don't export it) */ | 131 | static void get_term_dimensions(struct winsize *ws) |
| 123 | static int term_rows(void) | ||
| 124 | { | 132 | { |
| 125 | char *lines_string = getenv("LINES"); | 133 | char *s = getenv("LINES"); |
| 126 | int n_lines; | 134 | |
| 127 | 135 | if (s != NULL) { | |
| 128 | if (lines_string && (n_lines = atoi(lines_string)) > 0) | 136 | ws->ws_row = atoi(s); |
| 129 | return n_lines; | 137 | s = getenv("COLUMNS"); |
| 130 | #ifdef TIOCGWINSZ | 138 | if (s != NULL) { |
| 131 | else { | 139 | ws->ws_col = atoi(s); |
| 132 | struct winsize ws; | 140 | if (ws->ws_row && ws->ws_col) |
| 133 | if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_row) | 141 | return; |
| 134 | return ws.ws_row; | 142 | } |
| 135 | } | 143 | } |
| 144 | #ifdef TIOCGWINSZ | ||
| 145 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | ||
| 146 | ws->ws_row && ws->ws_col) | ||
| 147 | return; | ||
| 136 | #endif | 148 | #endif |
| 137 | return 25; | 149 | ws->ws_row = 25; |
| 150 | ws->ws_col = 80; | ||
| 138 | } | 151 | } |
| 139 | 152 | ||
| 140 | static void update_print_entries(void) | 153 | static void update_print_entries(struct winsize *ws) |
| 141 | { | 154 | { |
| 142 | print_entries = term_rows(); | 155 | print_entries = ws->ws_row; |
| 156 | |||
| 143 | if (print_entries > 9) | 157 | if (print_entries > 9) |
| 144 | print_entries -= 9; | 158 | print_entries -= 9; |
| 145 | } | 159 | } |
| 146 | 160 | ||
| 147 | static void sig_winch_handler(int sig __used) | 161 | static void sig_winch_handler(int sig __used) |
| 148 | { | 162 | { |
| 149 | update_print_entries(); | 163 | get_term_dimensions(&winsize); |
| 164 | update_print_entries(&winsize); | ||
| 150 | } | 165 | } |
| 151 | 166 | ||
| 152 | static void parse_source(struct sym_entry *syme) | 167 | static void parse_source(struct sym_entry *syme) |
| @@ -423,6 +438,8 @@ static void print_sym_table(void) | |||
| 423 | struct sym_entry *syme, *n; | 438 | struct sym_entry *syme, *n; |
| 424 | struct rb_root tmp = RB_ROOT; | 439 | struct rb_root tmp = RB_ROOT; |
| 425 | struct rb_node *nd; | 440 | struct rb_node *nd; |
| 441 | int sym_width = 0, dso_width; | ||
| 442 | const int win_width = winsize.ws_col - 1; | ||
| 426 | 443 | ||
| 427 | samples = userspace_samples = 0; | 444 | samples = userspace_samples = 0; |
| 428 | 445 | ||
| @@ -434,6 +451,7 @@ static void print_sym_table(void) | |||
| 434 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { | 451 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { |
| 435 | syme->snap_count = syme->count[snap]; | 452 | syme->snap_count = syme->count[snap]; |
| 436 | if (syme->snap_count != 0) { | 453 | if (syme->snap_count != 0) { |
| 454 | |||
| 437 | if ((hide_user_symbols && | 455 | if ((hide_user_symbols && |
| 438 | syme->origin == PERF_RECORD_MISC_USER) || | 456 | syme->origin == PERF_RECORD_MISC_USER) || |
| 439 | (hide_kernel_symbols && | 457 | (hide_kernel_symbols && |
| @@ -453,8 +471,7 @@ static void print_sym_table(void) | |||
| 453 | 471 | ||
| 454 | puts(CONSOLE_CLEAR); | 472 | puts(CONSOLE_CLEAR); |
| 455 | 473 | ||
| 456 | printf( | 474 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
| 457 | "------------------------------------------------------------------------------\n"); | ||
| 458 | printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", | 475 | printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", |
| 459 | samples_per_sec, | 476 | samples_per_sec, |
| 460 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); | 477 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); |
| @@ -492,26 +509,44 @@ static void print_sym_table(void) | |||
| 492 | printf(", %d CPUs)\n", nr_cpus); | 509 | printf(", %d CPUs)\n", nr_cpus); |
| 493 | } | 510 | } |
| 494 | 511 | ||
| 495 | printf("------------------------------------------------------------------------------\n\n"); | 512 | printf("%-*.*s\n\n", win_width, win_width, graph_dotted_line); |
| 496 | 513 | ||
| 497 | if (sym_filter_entry) { | 514 | if (sym_filter_entry) { |
| 498 | show_details(sym_filter_entry); | 515 | show_details(sym_filter_entry); |
| 499 | return; | 516 | return; |
| 500 | } | 517 | } |
| 501 | 518 | ||
| 519 | /* | ||
| 520 | * Find the longest symbol name that will be displayed | ||
| 521 | */ | ||
| 522 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { | ||
| 523 | syme = rb_entry(nd, struct sym_entry, rb_node); | ||
| 524 | if (++printed > print_entries || | ||
| 525 | (int)syme->snap_count < count_filter) | ||
| 526 | continue; | ||
| 527 | |||
| 528 | if (syme->name_len > sym_width) | ||
| 529 | sym_width = syme->name_len; | ||
| 530 | } | ||
| 531 | |||
| 532 | printed = 0; | ||
| 533 | |||
| 502 | if (nr_counters == 1) | 534 | if (nr_counters == 1) |
| 503 | printf(" samples pcnt"); | 535 | printf(" samples pcnt"); |
| 504 | else | 536 | else |
| 505 | printf(" weight samples pcnt"); | 537 | printf(" weight samples pcnt"); |
| 506 | 538 | ||
| 539 | dso_width = winsize.ws_col - sym_width - 29; | ||
| 540 | |||
| 507 | if (verbose) | 541 | if (verbose) |
| 508 | printf(" RIP "); | 542 | printf(" RIP "); |
| 509 | printf(" function DSO\n"); | 543 | printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); |
| 510 | printf(" %s _______ _____", | 544 | printf(" %s _______ _____", |
| 511 | nr_counters == 1 ? " " : "______"); | 545 | nr_counters == 1 ? " " : "______"); |
| 512 | if (verbose) | 546 | if (verbose) |
| 513 | printf(" ________________"); | 547 | printf(" ________________"); |
| 514 | printf(" ________________________________ ________________\n\n"); | 548 | printf(" %-*.*s %-*.*s\n\n", sym_width, sym_width, graph_line, |
| 549 | dso_width, dso_width, graph_line); | ||
| 515 | 550 | ||
| 516 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { | 551 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { |
| 517 | struct symbol *sym; | 552 | struct symbol *sym; |
| @@ -534,8 +569,11 @@ static void print_sym_table(void) | |||
| 534 | percent_color_fprintf(stdout, "%4.1f%%", pcnt); | 569 | percent_color_fprintf(stdout, "%4.1f%%", pcnt); |
| 535 | if (verbose) | 570 | if (verbose) |
| 536 | printf(" %016llx", sym->start); | 571 | printf(" %016llx", sym->start); |
| 537 | printf(" %-32s", sym->name); | 572 | printf(" %-*.*s", sym_width, sym_width, sym->name); |
| 538 | printf(" %s", syme->map->dso->short_name); | 573 | printf(" %-*.*s", dso_width, dso_width, |
| 574 | dso_width >= syme->map->dso->long_name_len ? | ||
| 575 | syme->map->dso->long_name : | ||
| 576 | syme->map->dso->short_name); | ||
| 539 | printf("\n"); | 577 | printf("\n"); |
| 540 | } | 578 | } |
| 541 | } | 579 | } |
| @@ -718,7 +756,7 @@ static void handle_keypress(int c) | |||
| 718 | case 'e': | 756 | case 'e': |
| 719 | prompt_integer(&print_entries, "Enter display entries (lines)"); | 757 | prompt_integer(&print_entries, "Enter display entries (lines)"); |
| 720 | if (print_entries == 0) { | 758 | if (print_entries == 0) { |
| 721 | update_print_entries(); | 759 | sig_winch_handler(SIGWINCH); |
| 722 | signal(SIGWINCH, sig_winch_handler); | 760 | signal(SIGWINCH, sig_winch_handler); |
| 723 | } else | 761 | } else |
| 724 | signal(SIGWINCH, SIG_DFL); | 762 | signal(SIGWINCH, SIG_DFL); |
| @@ -862,6 +900,9 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
| 862 | } | 900 | } |
| 863 | } | 901 | } |
| 864 | 902 | ||
| 903 | if (!syme->skip) | ||
| 904 | syme->name_len = strlen(sym->name); | ||
| 905 | |||
| 865 | return 0; | 906 | return 0; |
| 866 | } | 907 | } |
| 867 | 908 | ||
| @@ -1301,8 +1342,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
| 1301 | if (target_pid != -1 || profile_cpu != -1) | 1342 | if (target_pid != -1 || profile_cpu != -1) |
| 1302 | nr_cpus = 1; | 1343 | nr_cpus = 1; |
| 1303 | 1344 | ||
| 1345 | get_term_dimensions(&winsize); | ||
| 1304 | if (print_entries == 0) { | 1346 | if (print_entries == 0) { |
| 1305 | update_print_entries(); | 1347 | update_print_entries(&winsize); |
| 1306 | signal(SIGWINCH, sig_winch_handler); | 1348 | signal(SIGWINCH, sig_winch_handler); |
| 1307 | } | 1349 | } |
| 1308 | 1350 | ||
