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 | ||