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