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>
This commit is contained in:
Denys Vlasenko 2012-09-21 13:04:37 +02:00
parent 3c62bbae94
commit 2fb8d0dee9
2 changed files with 110 additions and 74 deletions

View File

@ -140,60 +140,6 @@ config BB_SYSCTL
help help
Configure kernel parameters at runtime. 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 config FEATURE_SHOW_THREADS
bool "Support for showing threads in ps/pstree/top" bool "Support for showing threads in ps/pstree/top"
default y default y

View File

@ -50,6 +50,60 @@
* chroot . ./top -bn1 >top1.out * 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" #include "libbb.h"
@ -101,6 +155,8 @@ struct globals {
#endif #endif
#if ENABLE_FEATURE_USE_TERMIOS #if ENABLE_FEATURE_USE_TERMIOS
struct termios initial_settings; struct termios initial_settings;
unsigned lines; /* screen height */
int scroll_ofs;
#endif #endif
#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
cmp_funcp sort_function[1]; cmp_funcp sort_function[1];
@ -117,6 +173,9 @@ struct globals {
/* Per CPU samples: current and last */ /* Per CPU samples: current and last */
jiffy_counts_t *cpu_jif, *cpu_prev_jif; jiffy_counts_t *cpu_jif, *cpu_prev_jif;
int num_cpus; int num_cpus;
#endif
#if ENABLE_FEATURE_USE_TERMIOS
char kbd_input[KEYCODE_BUFFER_SIZE];
#endif #endif
char line_buf[80]; char line_buf[80];
}; //FIX_ALIASING; - large code growth }; //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 */ /* Ok, all preliminary data is ready, go through the list */
scr_width += 2; /* account for leading '\n' and trailing NUL */ scr_width += 2; /* account for leading '\n' and trailing NUL */
if (lines_rem > ntop) if (lines_rem > ntop - G.scroll_ofs)
lines_rem = ntop; lines_rem = ntop - G.scroll_ofs;
s = top; s = top + G.scroll_ofs;
while (--lines_rem >= 0) { while (--lines_rem >= 0) {
unsigned col; unsigned col;
CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
@ -649,7 +708,6 @@ static void clearmems(void)
clear_username_cache(); clear_username_cache();
free(top); free(top);
top = NULL; top = NULL;
ntop = 0;
} }
#if ENABLE_FEATURE_USE_TERMIOS #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 HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK"
#define MIN_WIDTH sizeof(HDR_STR) #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); display_topmem_header(scr_width, &lines_rem);
strcpy(line_buf, HDR_STR " COMMAND"); 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); printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf);
lines_rem--; lines_rem--;
if (lines_rem > ntop) if (lines_rem > ntop - G.scroll_ofs)
lines_rem = ntop; lines_rem = ntop - G.scroll_ofs;
while (--lines_rem >= 0) { while (--lines_rem >= 0) {
/* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */
ulltoa6_and_space(s->pid , &line_buf[0*6]); ulltoa6_and_space(s->pid , &line_buf[0*6]);
@ -856,26 +914,57 @@ enum {
#if ENABLE_FEATURE_USE_TERMIOS #if ENABLE_FEATURE_USE_TERMIOS
static unsigned handle_input(unsigned scan_mask, unsigned interval) static unsigned handle_input(unsigned scan_mask, unsigned interval)
{ {
unsigned char c;
struct pollfd pfd[1]; struct pollfd pfd[1];
pfd[0].fd = 0; pfd[0].fd = 0;
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
while (1) { while (1) {
if (safe_poll(pfd, 1, interval * 1000) <= 0) int32_t c;
return scan_mask;
interval = 0;
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; option_mask32 |= OPT_EOF;
return scan_mask; break;
} }
interval = 0;
if (c == initial_settings.c_cc[VINTR]) if (c == initial_settings.c_cc[VINTR])
return EXIT_MASK; return EXIT_MASK;
if (c == initial_settings.c_cc[VEOF]) if (c == initial_settings.c_cc[VEOF])
return EXIT_MASK; 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 */ c |= 0x20; /* lowercase */
if (c == 'q') if (c == 'q')
return EXIT_MASK; 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 top_main(int argc UNUSED_PARAM, char **argv)
{ {
int iterations; int iterations;
unsigned lines, col; unsigned col;
unsigned interval; unsigned interval;
char *str_interval, *str_iterations; char *str_interval, *str_iterations;
unsigned scan_mask = TOP_MASK; unsigned scan_mask = TOP_MASK;
@ -1081,15 +1170,15 @@ int top_main(int argc UNUSED_PARAM, char **argv)
procps_status_t *p = NULL; procps_status_t *p = NULL;
if (OPT_BATCH_MODE) { if (OPT_BATCH_MODE) {
lines = INT_MAX; G.lines = INT_MAX;
col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */
} else { } else {
lines = 24; /* default */ G.lines = 24; /* default */
col = 79; col = 79;
#if ENABLE_FEATURE_USE_TERMIOS #if ENABLE_FEATURE_USE_TERMIOS
/* We output to stdout, we need size of stdout (not stdin)! */ /* We output to stdout, we need size of stdout (not stdin)! */
get_terminal_width_height(STDOUT_FILENO, &col, &lines); get_terminal_width_height(STDOUT_FILENO, &col, &G.lines);
if (lines < 5 || col < 10) { if (G.lines < 5 || col < 10) {
sleep(interval); sleep(interval);
continue; continue;
} }
@ -1099,6 +1188,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
} }
/* read process IDs & status for all the processes */ /* read process IDs & status for all the processes */
ntop = 0;
while ((p = procps_scan(p, scan_mask)) != NULL) { while ((p = procps_scan(p, scan_mask)) != NULL) {
int n; int n;
#if ENABLE_FEATURE_TOPMEM #if ENABLE_FEATURE_TOPMEM
@ -1165,10 +1255,10 @@ int top_main(int argc UNUSED_PARAM, char **argv)
} }
#endif #endif
if (scan_mask != TOPMEM_MASK) if (scan_mask != TOPMEM_MASK)
display_process_list(lines, col); display_process_list(G.lines, col);
#if ENABLE_FEATURE_TOPMEM #if ENABLE_FEATURE_TOPMEM
else else
display_topmem_process_list(lines, col); display_topmem_process_list(G.lines, col);
#endif #endif
clearmems(); clearmems();
if (iterations >= 0 && !--iterations) if (iterations >= 0 && !--iterations)