diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2012-09-21 13:04:37 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2012-09-21 13:04:37 +0200 |
| commit | 2fb8d0dee974622c52e446a02d066cccc4768bbf (patch) | |
| tree | 1158413d0b22e62a8ffb8bfc5a85df568af82a00 | |
| parent | 3c62bbae94642e6d05bc9f900bbdb5173d26cc51 (diff) | |
| download | busybox-w32-2fb8d0dee974622c52e446a02d066cccc4768bbf.tar.gz busybox-w32-2fb8d0dee974622c52e446a02d066cccc4768bbf.tar.bz2 busybox-w32-2fb8d0dee974622c52e446a02d066cccc4768bbf.zip | |
top: implement scrolling up/down (_very_ useful)
function old new delta
handle_input 494 564 +70
top_main 928 947 +19
display_topmem_process_list 363 381 +18
display_process_list 1442 1453 +11
clearmems 38 28 -10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/1 up/down: 118/-10) Total: 108 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | procps/Config.src | 54 | ||||
| -rw-r--r-- | procps/top.c | 130 |
2 files changed, 110 insertions, 74 deletions
diff --git a/procps/Config.src b/procps/Config.src index 5cd47c84f..527d9ee0c 100644 --- a/procps/Config.src +++ b/procps/Config.src | |||
| @@ -140,60 +140,6 @@ config BB_SYSCTL | |||
| 140 | help | 140 | help |
| 141 | Configure kernel parameters at runtime. | 141 | Configure kernel parameters at runtime. |
| 142 | 142 | ||
| 143 | config TOP | ||
| 144 | bool "top" | ||
| 145 | default y | ||
| 146 | help | ||
| 147 | The top program provides a dynamic real-time view of a running | ||
| 148 | system. | ||
| 149 | |||
| 150 | config FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 151 | bool "Show CPU per-process usage percentage" | ||
| 152 | default y | ||
| 153 | depends on TOP | ||
| 154 | help | ||
| 155 | Make top display CPU usage for each process. | ||
| 156 | This adds about 2k. | ||
| 157 | |||
| 158 | config FEATURE_TOP_CPU_GLOBAL_PERCENTS | ||
| 159 | bool "Show CPU global usage percentage" | ||
| 160 | default y | ||
| 161 | depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 162 | help | ||
| 163 | Makes top display "CPU: NN% usr NN% sys..." line. | ||
| 164 | This adds about 0.5k. | ||
| 165 | |||
| 166 | config FEATURE_TOP_SMP_CPU | ||
| 167 | bool "SMP CPU usage display ('c' key)" | ||
| 168 | default y | ||
| 169 | depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS | ||
| 170 | help | ||
| 171 | Allow 'c' key to switch between individual/cumulative CPU stats | ||
| 172 | This adds about 0.5k. | ||
| 173 | |||
| 174 | config FEATURE_TOP_DECIMALS | ||
| 175 | bool "Show 1/10th of a percent in CPU/mem statistics" | ||
| 176 | default y | ||
| 177 | depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 178 | help | ||
| 179 | Show 1/10th of a percent in CPU/mem statistics. | ||
| 180 | This adds about 0.3k. | ||
| 181 | |||
| 182 | config FEATURE_TOP_SMP_PROCESS | ||
| 183 | bool "Show CPU process runs on ('j' field)" | ||
| 184 | default y | ||
| 185 | depends on TOP | ||
| 186 | help | ||
| 187 | Show CPU where process was last found running on. | ||
| 188 | This is the 'j' field. | ||
| 189 | |||
| 190 | config FEATURE_TOPMEM | ||
| 191 | bool "Topmem command ('s' key)" | ||
| 192 | default y | ||
| 193 | depends on TOP | ||
| 194 | help | ||
| 195 | Enable 's' in top (gives lots of memory info). | ||
| 196 | |||
| 197 | config FEATURE_SHOW_THREADS | 143 | config FEATURE_SHOW_THREADS |
| 198 | bool "Support for showing threads in ps/pstree/top" | 144 | bool "Support for showing threads in ps/pstree/top" |
| 199 | default y | 145 | default y |
diff --git a/procps/top.c b/procps/top.c index 15eb624cc..00cb44896 100644 --- a/procps/top.c +++ b/procps/top.c | |||
| @@ -50,6 +50,60 @@ | |||
| 50 | * chroot . ./top -bn1 >top1.out | 50 | * chroot . ./top -bn1 >top1.out |
| 51 | */ | 51 | */ |
| 52 | 52 | ||
| 53 | //config:config TOP | ||
| 54 | //config: bool "top" | ||
| 55 | //config: default y | ||
| 56 | //config: help | ||
| 57 | //config: The top program provides a dynamic real-time view of a running | ||
| 58 | //config: system. | ||
| 59 | //config: | ||
| 60 | //config:config FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 61 | //config: bool "Show CPU per-process usage percentage" | ||
| 62 | //config: default y | ||
| 63 | //config: depends on TOP | ||
| 64 | //config: help | ||
| 65 | //config: Make top display CPU usage for each process. | ||
| 66 | //config: This adds about 2k. | ||
| 67 | //config: | ||
| 68 | //config:config FEATURE_TOP_CPU_GLOBAL_PERCENTS | ||
| 69 | //config: bool "Show CPU global usage percentage" | ||
| 70 | //config: default y | ||
| 71 | //config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 72 | //config: help | ||
| 73 | //config: Makes top display "CPU: NN% usr NN% sys..." line. | ||
| 74 | //config: This adds about 0.5k. | ||
| 75 | //config: | ||
| 76 | //config:config FEATURE_TOP_SMP_CPU | ||
| 77 | //config: bool "SMP CPU usage display ('c' key)" | ||
| 78 | //config: default y | ||
| 79 | //config: depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS | ||
| 80 | //config: help | ||
| 81 | //config: Allow 'c' key to switch between individual/cumulative CPU stats | ||
| 82 | //config: This adds about 0.5k. | ||
| 83 | //config: | ||
| 84 | //config:config FEATURE_TOP_DECIMALS | ||
| 85 | //config: bool "Show 1/10th of a percent in CPU/mem statistics" | ||
| 86 | //config: default y | ||
| 87 | //config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
| 88 | //config: help | ||
| 89 | //config: Show 1/10th of a percent in CPU/mem statistics. | ||
| 90 | //config: This adds about 0.3k. | ||
| 91 | //config: | ||
| 92 | //config:config FEATURE_TOP_SMP_PROCESS | ||
| 93 | //config: bool "Show CPU process runs on ('j' field)" | ||
| 94 | //config: default y | ||
| 95 | //config: depends on TOP | ||
| 96 | //config: help | ||
| 97 | //config: Show CPU where process was last found running on. | ||
| 98 | //config: This is the 'j' field. | ||
| 99 | //config: | ||
| 100 | //config:config FEATURE_TOPMEM | ||
| 101 | //config: bool "Topmem command ('s' key)" | ||
| 102 | //config: default y | ||
| 103 | //config: depends on TOP | ||
| 104 | //config: help | ||
| 105 | //config: Enable 's' in top (gives lots of memory info). | ||
| 106 | |||
| 53 | #include "libbb.h" | 107 | #include "libbb.h" |
| 54 | 108 | ||
| 55 | 109 | ||
| @@ -101,6 +155,8 @@ struct globals { | |||
| 101 | #endif | 155 | #endif |
| 102 | #if ENABLE_FEATURE_USE_TERMIOS | 156 | #if ENABLE_FEATURE_USE_TERMIOS |
| 103 | struct termios initial_settings; | 157 | struct termios initial_settings; |
| 158 | unsigned lines; /* screen height */ | ||
| 159 | int scroll_ofs; | ||
| 104 | #endif | 160 | #endif |
| 105 | #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 161 | #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| 106 | cmp_funcp sort_function[1]; | 162 | cmp_funcp sort_function[1]; |
| @@ -118,6 +174,9 @@ struct globals { | |||
| 118 | jiffy_counts_t *cpu_jif, *cpu_prev_jif; | 174 | jiffy_counts_t *cpu_jif, *cpu_prev_jif; |
| 119 | int num_cpus; | 175 | int num_cpus; |
| 120 | #endif | 176 | #endif |
| 177 | #if ENABLE_FEATURE_USE_TERMIOS | ||
| 178 | char kbd_input[KEYCODE_BUFFER_SIZE]; | ||
| 179 | #endif | ||
| 121 | char line_buf[80]; | 180 | char line_buf[80]; |
| 122 | }; //FIX_ALIASING; - large code growth | 181 | }; //FIX_ALIASING; - large code growth |
| 123 | enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; | 182 | enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; |
| @@ -602,9 +661,9 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) | |||
| 602 | 661 | ||
| 603 | /* Ok, all preliminary data is ready, go through the list */ | 662 | /* Ok, all preliminary data is ready, go through the list */ |
| 604 | scr_width += 2; /* account for leading '\n' and trailing NUL */ | 663 | scr_width += 2; /* account for leading '\n' and trailing NUL */ |
| 605 | if (lines_rem > ntop) | 664 | if (lines_rem > ntop - G.scroll_ofs) |
| 606 | lines_rem = ntop; | 665 | lines_rem = ntop - G.scroll_ofs; |
| 607 | s = top; | 666 | s = top + G.scroll_ofs; |
| 608 | while (--lines_rem >= 0) { | 667 | while (--lines_rem >= 0) { |
| 609 | unsigned col; | 668 | unsigned col; |
| 610 | CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); | 669 | CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); |
| @@ -649,7 +708,6 @@ static void clearmems(void) | |||
| 649 | clear_username_cache(); | 708 | clear_username_cache(); |
| 650 | free(top); | 709 | free(top); |
| 651 | top = NULL; | 710 | top = NULL; |
| 652 | ntop = 0; | ||
| 653 | } | 711 | } |
| 654 | 712 | ||
| 655 | #if ENABLE_FEATURE_USE_TERMIOS | 713 | #if ENABLE_FEATURE_USE_TERMIOS |
| @@ -793,7 +851,7 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | |||
| 793 | { | 851 | { |
| 794 | #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" | 852 | #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" |
| 795 | #define MIN_WIDTH sizeof(HDR_STR) | 853 | #define MIN_WIDTH sizeof(HDR_STR) |
| 796 | const topmem_status_t *s = topmem; | 854 | const topmem_status_t *s = topmem + G.scroll_ofs; |
| 797 | 855 | ||
| 798 | display_topmem_header(scr_width, &lines_rem); | 856 | display_topmem_header(scr_width, &lines_rem); |
| 799 | strcpy(line_buf, HDR_STR " COMMAND"); | 857 | strcpy(line_buf, HDR_STR " COMMAND"); |
| @@ -801,8 +859,8 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | |||
| 801 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); | 859 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); |
| 802 | lines_rem--; | 860 | lines_rem--; |
| 803 | 861 | ||
| 804 | if (lines_rem > ntop) | 862 | if (lines_rem > ntop - G.scroll_ofs) |
| 805 | lines_rem = ntop; | 863 | lines_rem = ntop - G.scroll_ofs; |
| 806 | while (--lines_rem >= 0) { | 864 | while (--lines_rem >= 0) { |
| 807 | /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ | 865 | /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ |
| 808 | ulltoa6_and_space(s->pid , &line_buf[0*6]); | 866 | ulltoa6_and_space(s->pid , &line_buf[0*6]); |
| @@ -856,26 +914,57 @@ enum { | |||
| 856 | #if ENABLE_FEATURE_USE_TERMIOS | 914 | #if ENABLE_FEATURE_USE_TERMIOS |
| 857 | static unsigned handle_input(unsigned scan_mask, unsigned interval) | 915 | static unsigned handle_input(unsigned scan_mask, unsigned interval) |
| 858 | { | 916 | { |
| 859 | unsigned char c; | ||
| 860 | struct pollfd pfd[1]; | 917 | struct pollfd pfd[1]; |
| 861 | 918 | ||
| 862 | pfd[0].fd = 0; | 919 | pfd[0].fd = 0; |
| 863 | pfd[0].events = POLLIN; | 920 | pfd[0].events = POLLIN; |
| 864 | 921 | ||
| 865 | while (1) { | 922 | while (1) { |
| 866 | if (safe_poll(pfd, 1, interval * 1000) <= 0) | 923 | int32_t c; |
| 867 | return scan_mask; | ||
| 868 | interval = 0; | ||
| 869 | 924 | ||
| 870 | if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ | 925 | c = read_key(STDIN_FILENO, G.kbd_input, interval * 1000); |
| 926 | if (c == -1 && errno != EAGAIN) { | ||
| 927 | /* error/EOF */ | ||
| 871 | option_mask32 |= OPT_EOF; | 928 | option_mask32 |= OPT_EOF; |
| 872 | return scan_mask; | 929 | break; |
| 873 | } | 930 | } |
| 931 | interval = 0; | ||
| 874 | 932 | ||
| 875 | if (c == initial_settings.c_cc[VINTR]) | 933 | if (c == initial_settings.c_cc[VINTR]) |
| 876 | return EXIT_MASK; | 934 | return EXIT_MASK; |
| 877 | if (c == initial_settings.c_cc[VEOF]) | 935 | if (c == initial_settings.c_cc[VEOF]) |
| 878 | return EXIT_MASK; | 936 | return EXIT_MASK; |
| 937 | |||
| 938 | if (c == KEYCODE_UP) { | ||
| 939 | G.scroll_ofs--; | ||
| 940 | goto normalize_ofs; | ||
| 941 | } | ||
| 942 | if (c == KEYCODE_DOWN) { | ||
| 943 | G.scroll_ofs++; | ||
| 944 | goto normalize_ofs; | ||
| 945 | } | ||
| 946 | if (c == KEYCODE_HOME) { | ||
| 947 | G.scroll_ofs = 0; | ||
| 948 | break; | ||
| 949 | } | ||
| 950 | if (c == KEYCODE_END) { | ||
| 951 | G.scroll_ofs = ntop - G.lines / 2; | ||
| 952 | goto normalize_ofs; | ||
| 953 | } | ||
| 954 | if (c == KEYCODE_PAGEUP) { | ||
| 955 | G.scroll_ofs -= G.lines / 2; | ||
| 956 | goto normalize_ofs; | ||
| 957 | } | ||
| 958 | if (c == KEYCODE_PAGEDOWN) { | ||
| 959 | G.scroll_ofs += G.lines / 2; | ||
| 960 | normalize_ofs: | ||
| 961 | if (G.scroll_ofs >= ntop) | ||
| 962 | G.scroll_ofs = ntop - 1; | ||
| 963 | if (G.scroll_ofs < 0) | ||
| 964 | G.scroll_ofs = 0; | ||
| 965 | break; | ||
| 966 | } | ||
| 967 | |||
| 879 | c |= 0x20; /* lowercase */ | 968 | c |= 0x20; /* lowercase */ |
| 880 | if (c == 'q') | 969 | if (c == 'q') |
| 881 | return EXIT_MASK; | 970 | return EXIT_MASK; |
| @@ -1011,7 +1100,7 @@ int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
| 1011 | int top_main(int argc UNUSED_PARAM, char **argv) | 1100 | int top_main(int argc UNUSED_PARAM, char **argv) |
| 1012 | { | 1101 | { |
| 1013 | int iterations; | 1102 | int iterations; |
| 1014 | unsigned lines, col; | 1103 | unsigned col; |
| 1015 | unsigned interval; | 1104 | unsigned interval; |
| 1016 | char *str_interval, *str_iterations; | 1105 | char *str_interval, *str_iterations; |
| 1017 | unsigned scan_mask = TOP_MASK; | 1106 | unsigned scan_mask = TOP_MASK; |
| @@ -1081,15 +1170,15 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
| 1081 | procps_status_t *p = NULL; | 1170 | procps_status_t *p = NULL; |
| 1082 | 1171 | ||
| 1083 | if (OPT_BATCH_MODE) { | 1172 | if (OPT_BATCH_MODE) { |
| 1084 | lines = INT_MAX; | 1173 | G.lines = INT_MAX; |
| 1085 | col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ | 1174 | col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ |
| 1086 | } else { | 1175 | } else { |
| 1087 | lines = 24; /* default */ | 1176 | G.lines = 24; /* default */ |
| 1088 | col = 79; | 1177 | col = 79; |
| 1089 | #if ENABLE_FEATURE_USE_TERMIOS | 1178 | #if ENABLE_FEATURE_USE_TERMIOS |
| 1090 | /* We output to stdout, we need size of stdout (not stdin)! */ | 1179 | /* We output to stdout, we need size of stdout (not stdin)! */ |
| 1091 | get_terminal_width_height(STDOUT_FILENO, &col, &lines); | 1180 | get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); |
| 1092 | if (lines < 5 || col < 10) { | 1181 | if (G.lines < 5 || col < 10) { |
| 1093 | sleep(interval); | 1182 | sleep(interval); |
| 1094 | continue; | 1183 | continue; |
| 1095 | } | 1184 | } |
| @@ -1099,6 +1188,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
| 1099 | } | 1188 | } |
| 1100 | 1189 | ||
| 1101 | /* read process IDs & status for all the processes */ | 1190 | /* read process IDs & status for all the processes */ |
| 1191 | ntop = 0; | ||
| 1102 | while ((p = procps_scan(p, scan_mask)) != NULL) { | 1192 | while ((p = procps_scan(p, scan_mask)) != NULL) { |
| 1103 | int n; | 1193 | int n; |
| 1104 | #if ENABLE_FEATURE_TOPMEM | 1194 | #if ENABLE_FEATURE_TOPMEM |
| @@ -1165,10 +1255,10 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
| 1165 | } | 1255 | } |
| 1166 | #endif | 1256 | #endif |
| 1167 | if (scan_mask != TOPMEM_MASK) | 1257 | if (scan_mask != TOPMEM_MASK) |
| 1168 | display_process_list(lines, col); | 1258 | display_process_list(G.lines, col); |
| 1169 | #if ENABLE_FEATURE_TOPMEM | 1259 | #if ENABLE_FEATURE_TOPMEM |
| 1170 | else | 1260 | else |
| 1171 | display_topmem_process_list(lines, col); | 1261 | display_topmem_process_list(G.lines, col); |
| 1172 | #endif | 1262 | #endif |
| 1173 | clearmems(); | 1263 | clearmems(); |
| 1174 | if (iterations >= 0 && !--iterations) | 1264 | if (iterations >= 0 && !--iterations) |
