top: implement scrolling up/down (_very_ useful)
No binary (build failed)
—
(log yok)
| @@ -140,60 +140,6 @@ config BB_SYSCTL | |
| help | |
| Configure kernel parameters at runtime. | |
| - | config TOP |
| - | bool "top" |
| - | default y |
| - | help |
| - | The top program provides a dynamic real-time view of a running |
| - | system. |
| - | |
| - | config FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | bool "Show CPU per-process usage percentage" |
| - | default y |
| - | depends on TOP |
| - | help |
| - | Make top display CPU usage for each process. |
| - | This adds about 2k. |
| - | |
| - | config FEATURE_TOP_CPU_GLOBAL_PERCENTS |
| - | bool "Show CPU global usage percentage" |
| - | default y |
| - | depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | help |
| - | Makes top display "CPU: NN% usr NN% sys..." line. |
| - | This adds about 0.5k. |
| - | |
| - | config FEATURE_TOP_SMP_CPU |
| - | bool "SMP CPU usage display ('c' key)" |
| - | default y |
| - | depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS |
| - | help |
| - | Allow 'c' key to switch between individual/cumulative CPU stats |
| - | This adds about 0.5k. |
| - | |
| - | config FEATURE_TOP_DECIMALS |
| - | bool "Show 1/10th of a percent in CPU/mem statistics" |
| - | default y |
| - | depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| - | help |
| - | Show 1/10th of a percent in CPU/mem statistics. |
| - | This adds about 0.3k. |
| - | |
| - | config FEATURE_TOP_SMP_PROCESS |
| - | bool "Show CPU process runs on ('j' field)" |
| - | default y |
| - | depends on TOP |
| - | help |
| - | Show CPU where process was last found running on. |
| - | This is the 'j' field. |
| - | |
| - | config FEATURE_TOPMEM |
| - | bool "Topmem command ('s' key)" |
| - | default y |
| - | depends on TOP |
| - | help |
| - | Enable 's' in top (gives lots of memory info). |
| - | |
| config FEATURE_SHOW_THREADS | |
| bool "Support for showing threads in ps/pstree/top" | |
| default y | |
| @@ -50,6 +50,60 @@ | |
| * chroot . ./top -bn1 >top1.out | |
| */ | |
| + | //config:config TOP |
| + | //config: bool "top" |
| + | //config: default y |
| + | //config: help |
| + | //config: The top program provides a dynamic real-time view of a running |
| + | //config: system. |
| + | //config: |
| + | //config:config FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| + | //config: bool "Show CPU per-process usage percentage" |
| + | //config: default y |
| + | //config: depends on TOP |
| + | //config: help |
| + | //config: Make top display CPU usage for each process. |
| + | //config: This adds about 2k. |
| + | //config: |
| + | //config:config FEATURE_TOP_CPU_GLOBAL_PERCENTS |
| + | //config: bool "Show CPU global usage percentage" |
| + | //config: default y |
| + | //config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| + | //config: help |
| + | //config: Makes top display "CPU: NN% usr NN% sys..." line. |
| + | //config: This adds about 0.5k. |
| + | //config: |
| + | //config:config FEATURE_TOP_SMP_CPU |
| + | //config: bool "SMP CPU usage display ('c' key)" |
| + | //config: default y |
| + | //config: depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS |
| + | //config: help |
| + | //config: Allow 'c' key to switch between individual/cumulative CPU stats |
| + | //config: This adds about 0.5k. |
| + | //config: |
| + | //config:config FEATURE_TOP_DECIMALS |
| + | //config: bool "Show 1/10th of a percent in CPU/mem statistics" |
| + | //config: default y |
| + | //config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE |
| + | //config: help |
| + | //config: Show 1/10th of a percent in CPU/mem statistics. |
| + | //config: This adds about 0.3k. |
| + | //config: |
| + | //config:config FEATURE_TOP_SMP_PROCESS |
| + | //config: bool "Show CPU process runs on ('j' field)" |
| + | //config: default y |
| + | //config: depends on TOP |
| + | //config: help |
| + | //config: Show CPU where process was last found running on. |
| + | //config: This is the 'j' field. |
| + | //config: |
| + | //config:config FEATURE_TOPMEM |
| + | //config: bool "Topmem command ('s' key)" |
| + | //config: default y |
| + | //config: depends on TOP |
| + | //config: help |
| + | //config: Enable 's' in top (gives lots of memory info). |
| + | |
| #include "libbb.h" | |
| @@ -101,6 +155,8 @@ struct globals { | |
| #endif | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| struct termios initial_settings; | |
| + | unsigned lines; /* screen height */ |
| + | int scroll_ofs; |
| #endif | |
| #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | |
| cmp_funcp sort_function[1]; | |
| @@ -117,6 +173,9 @@ struct globals { | |
| /* Per CPU samples: current and last */ | |
| jiffy_counts_t *cpu_jif, *cpu_prev_jif; | |
| int num_cpus; | |
| + | #endif |
| + | #if ENABLE_FEATURE_USE_TERMIOS |
| + | char kbd_input[KEYCODE_BUFFER_SIZE]; |
| #endif | |
| char line_buf[80]; | |
| }; //FIX_ALIASING; - large code growth | |
| @@ -602,9 +661,9 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) | |
| /* Ok, all preliminary data is ready, go through the list */ | |
| scr_width += 2; /* account for leading '\n' and trailing NUL */ | |
| - | if (lines_rem > ntop) |
| - | lines_rem = ntop; |
| - | s = top; |
| + | if (lines_rem > ntop - G.scroll_ofs) |
| + | lines_rem = ntop - G.scroll_ofs; |
| + | s = top + G.scroll_ofs; |
| while (--lines_rem >= 0) { | |
| unsigned col; | |
| CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); | |
| @@ -649,7 +708,6 @@ static void clearmems(void) | |
| clear_username_cache(); | |
| free(top); | |
| top = NULL; | |
| - | ntop = 0; |
| } | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| @@ -793,7 +851,7 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | |
| { | |
| #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" | |
| #define MIN_WIDTH sizeof(HDR_STR) | |
| - | const topmem_status_t *s = topmem; |
| + | const topmem_status_t *s = topmem + G.scroll_ofs; |
| display_topmem_header(scr_width, &lines_rem); | |
| strcpy(line_buf, HDR_STR " COMMAND"); | |
| @@ -801,8 +859,8 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | |
| printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); | |
| lines_rem--; | |
| - | if (lines_rem > ntop) |
| - | lines_rem = ntop; |
| + | if (lines_rem > ntop - G.scroll_ofs) |
| + | lines_rem = ntop - G.scroll_ofs; |
| while (--lines_rem >= 0) { | |
| /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ | |
| ulltoa6_and_space(s->pid , &line_buf[0*6]); | |
| @@ -856,26 +914,57 @@ enum { | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| static unsigned handle_input(unsigned scan_mask, unsigned interval) | |
| { | |
| - | unsigned char c; |
| struct pollfd pfd[1]; | |
| pfd[0].fd = 0; | |
| pfd[0].events = POLLIN; | |
| while (1) { | |
| - | if (safe_poll(pfd, 1, interval * 1000) <= 0) |
| - | return scan_mask; |
| - | interval = 0; |
| + | int32_t c; |
| - | if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ |
| + | c = read_key(STDIN_FILENO, G.kbd_input, interval * 1000); |
| + | if (c == -1 && errno != EAGAIN) { |
| + | /* error/EOF */ |
| option_mask32 |= OPT_EOF; | |
| - | return scan_mask; |
| + | break; |
| } | |
| + | interval = 0; |
| if (c == initial_settings.c_cc[VINTR]) | |
| return EXIT_MASK; | |
| if (c == initial_settings.c_cc[VEOF]) | |
| return EXIT_MASK; | |
| + | |
| + | if (c == KEYCODE_UP) { |
| + | G.scroll_ofs--; |
| + | goto normalize_ofs; |
| + | } |
| + | if (c == KEYCODE_DOWN) { |
| + | G.scroll_ofs++; |
| + | goto normalize_ofs; |
| + | } |
| + | if (c == KEYCODE_HOME) { |
| + | G.scroll_ofs = 0; |
| + | break; |
| + | } |
| + | if (c == KEYCODE_END) { |
| + | G.scroll_ofs = ntop - G.lines / 2; |
| + | goto normalize_ofs; |
| + | } |
| + | if (c == KEYCODE_PAGEUP) { |
| + | G.scroll_ofs -= G.lines / 2; |
| + | goto normalize_ofs; |
| + | } |
| + | if (c == KEYCODE_PAGEDOWN) { |
| + | G.scroll_ofs += G.lines / 2; |
| + | normalize_ofs: |
| + | if (G.scroll_ofs >= ntop) |
| + | G.scroll_ofs = ntop - 1; |
| + | if (G.scroll_ofs < 0) |
| + | G.scroll_ofs = 0; |
| + | break; |
| + | } |
| + | |
| c |= 0x20; /* lowercase */ | |
| if (c == 'q') | |
| return EXIT_MASK; | |
| @@ -1011,7 +1100,7 @@ int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int top_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| int iterations; | |
| - | unsigned lines, col; |
| + | unsigned col; |
| unsigned interval; | |
| char *str_interval, *str_iterations; | |
| unsigned scan_mask = TOP_MASK; | |
| @@ -1081,15 +1170,15 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| procps_status_t *p = NULL; | |
| if (OPT_BATCH_MODE) { | |
| - | lines = INT_MAX; |
| + | G.lines = INT_MAX; |
| col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ | |
| } else { | |
| - | lines = 24; /* default */ |
| + | G.lines = 24; /* default */ |
| col = 79; | |
| #if ENABLE_FEATURE_USE_TERMIOS | |
| /* We output to stdout, we need size of stdout (not stdin)! */ | |
| - | get_terminal_width_height(STDOUT_FILENO, &col, &lines); |
| - | if (lines < 5 || col < 10) { |
| + | get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); |
| + | if (G.lines < 5 || col < 10) { |
| sleep(interval); | |
| continue; | |
| } | |
| @@ -1099,6 +1188,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| /* read process IDs & status for all the processes */ | |
| + | ntop = 0; |
| while ((p = procps_scan(p, scan_mask)) != NULL) { | |
| int n; | |
| #if ENABLE_FEATURE_TOPMEM | |
| @@ -1165,10 +1255,10 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| #endif | |
| if (scan_mask != TOPMEM_MASK) | |
| - | display_process_list(lines, col); |
| + | display_process_list(G.lines, col); |
| #if ENABLE_FEATURE_TOPMEM | |
| else | |
| - | display_topmem_process_list(lines, col); |
| + | display_topmem_process_list(G.lines, col); |
| #endif | |
| clearmems(); | |
| if (iterations >= 0 && !--iterations) | |