diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-19 02:16:10 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-19 02:16:10 +0100 |
| commit | afb92adf474bc313bad184ed1f3fee06455fb23f (patch) | |
| tree | 4afa6d20b6720dfd992284bffb0e951ac826de7f | |
| parent | fd2ce3fa2710659721983ec06abb0252ffa086ea (diff) | |
| download | busybox-w32-afb92adf474bc313bad184ed1f3fee06455fb23f.tar.gz busybox-w32-afb92adf474bc313bad184ed1f3fee06455fb23f.tar.bz2 busybox-w32-afb92adf474bc313bad184ed1f3fee06455fb23f.zip | |
vmstat: smarter handling of header re-printing
function old new delta
vmstat_main 230 559 +329
print_row 340 - -340
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/0 up/down: 329/-340) Total: -11 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | procps/vmstat.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/procps/vmstat.c b/procps/vmstat.c index f479dbecf..79ee59b1e 100644 --- a/procps/vmstat.c +++ b/procps/vmstat.c | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | * Licensed under GPLv2, see file LICENSE in this source tree. | 7 | * Licensed under GPLv2, see file LICENSE in this source tree. |
| 8 | */ | 8 | */ |
| 9 | //config:config VMSTAT | 9 | //config:config VMSTAT |
| 10 | //config: bool "vmstat (3 kb)" | 10 | //config: bool "vmstat (2 kb)" |
| 11 | //config: default y | 11 | //config: default y |
| 12 | //config: help | 12 | //config: help |
| 13 | //config: Report virtual memory statistics | 13 | //config: Report virtual memory statistics |
| @@ -49,6 +49,8 @@ L("procs\0") "\2" L("r\0" )FROM_PROC_STAT M_DECREMENT "procs_running\ | |||
| 49 | "\2" L("b\0" )FROM_PROC_STAT "procs_blocked\0" | 49 | "\2" L("b\0" )FROM_PROC_STAT "procs_blocked\0" |
| 50 | L("memory\0") "\6" L("swpd\0" )FROM_PROC_MEMINFO PSEUDO_SWPD "\0" | 50 | L("memory\0") "\6" L("swpd\0" )FROM_PROC_MEMINFO PSEUDO_SWPD "\0" |
| 51 | "\6" L("free\0" )FROM_PROC_MEMINFO "MemFree\0" | 51 | "\6" L("free\0" )FROM_PROC_MEMINFO "MemFree\0" |
| 52 | //TODO? "MemAvailable" in newer kernels may be a more useful indicator how much memory is "free" | ||
| 53 | //in the sense of being immediately availabe if allocation demand arises (e.g. by dropping cached filesystem data) | ||
| 52 | "\6" L("buff\0" )FROM_PROC_MEMINFO "Buffers\0" | 54 | "\6" L("buff\0" )FROM_PROC_MEMINFO "Buffers\0" |
| 53 | "\6" L("cache\0")FROM_PROC_MEMINFO PSEUDO_CACHE "\0" | 55 | "\6" L("cache\0")FROM_PROC_MEMINFO PSEUDO_CACHE "\0" |
| 54 | L("swap\0") "\4" L("si\0" )FROM_PROC_VMSTAT M_DELTA "pswpin\0" | 56 | L("swap\0") "\4" L("si\0" )FROM_PROC_VMSTAT M_DELTA "pswpin\0" |
| @@ -65,6 +67,8 @@ L("cpu\0") "\2" L("us\0" )FROM_PROC_STAT_CPU M_DPERCENT "\x0d" /* user | |||
| 65 | // "gu"est columnt seems to be added in procps-ng 4.x.x (it makes the output not 80, but 83 chars): | 67 | // "gu"est columnt seems to be added in procps-ng 4.x.x (it makes the output not 80, but 83 chars): |
| 66 | "\2" L("gu\0" )FROM_PROC_STAT_CPU M_DPERCENT "\x0c" /* guest */ | 68 | "\2" L("gu\0" )FROM_PROC_STAT_CPU M_DPERCENT "\x0c" /* guest */ |
| 67 | ; | 69 | ; |
| 70 | /* Number of columns defined in coldescs[] */ | ||
| 71 | #define NCOLS (2+4+2+2+2+6) | ||
| 68 | /* Packed row data from coldescs[] is decoded into this structure */ | 72 | /* Packed row data from coldescs[] is decoded into this structure */ |
| 69 | struct col { | 73 | struct col { |
| 70 | L(const char *grplabel;) | 74 | L(const char *grplabel;) |
| @@ -78,13 +82,9 @@ struct col { | |||
| 78 | #define MOD_DECREMENT 0x04 | 82 | #define MOD_DECREMENT 0x04 |
| 79 | }; | 83 | }; |
| 80 | 84 | ||
| 81 | /* Number of columns defined in coldescs[] */ | ||
| 82 | #define NCOLS (2+4+2+2+2+6) | ||
| 83 | |||
| 84 | /* Globals. Sort by size and access frequency. */ | ||
| 85 | struct globals { | 85 | struct globals { |
| 86 | unsigned data1[NCOLS]; | 86 | unsigned data[NCOLS]; |
| 87 | unsigned data2[NCOLS]; | 87 | unsigned prev[NCOLS]; |
| 88 | }; | 88 | }; |
| 89 | #define G (*(struct globals*)bb_common_bufsiz1) | 89 | #define G (*(struct globals*)bb_common_bufsiz1) |
| 90 | #define INIT_G() do { \ | 90 | #define INIT_G() do { \ |
| @@ -419,7 +419,6 @@ static void print_header(void) | |||
| 419 | #if FIXED_HEADER | 419 | #if FIXED_HEADER |
| 420 | /* The header is constant yet and can be hardcoded instead, | 420 | /* The header is constant yet and can be hardcoded instead, |
| 421 | * but adding options such as -wtd to match upstream will change that */ | 421 | * but adding options such as -wtd to match upstream will change that */ |
| 422 | //TODO: remove grplabel/label from coldescs[], they are unused | ||
| 423 | puts( | 422 | puts( |
| 424 | "procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------""\n" | 423 | "procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------""\n" |
| 425 | " r b swpd free buff cache si so bi bo in cs us sy id wa st gu" | 424 | " r b swpd free buff cache si so bi bo in cs us sy id wa st gu" |
| @@ -480,16 +479,18 @@ int vmstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
| 480 | int vmstat_main(int argc UNUSED_PARAM, char **argv) | 479 | int vmstat_main(int argc UNUSED_PARAM, char **argv) |
| 481 | { | 480 | { |
| 482 | int opt; | 481 | int opt; |
| 483 | unsigned interval = 0; | 482 | unsigned interval; |
| 484 | int count = 1; | 483 | int count; |
| 485 | unsigned height; | 484 | unsigned height; |
| 486 | unsigned rows; | 485 | int row; |
| 487 | 486 | ||
| 488 | INIT_G(); | 487 | INIT_G(); |
| 489 | 488 | ||
| 490 | /* Parse and process arguments */ | 489 | /* Parse and process arguments */ |
| 491 | opt = getopt32(argv, "n"); | 490 | opt = getopt32(argv, "n"); |
| 492 | argv += optind; | 491 | argv += optind; |
| 492 | interval = 0; | ||
| 493 | count = 1; | ||
| 493 | if (*argv) { | 494 | if (*argv) { |
| 494 | interval = xatoi_positive(*argv); | 495 | interval = xatoi_positive(*argv); |
| 495 | count = (interval != 0 ? -1 : 1); | 496 | count = (interval != 0 ? -1 : 1); |
| @@ -500,23 +501,29 @@ int vmstat_main(int argc UNUSED_PARAM, char **argv) | |||
| 500 | 501 | ||
| 501 | /* Prepare to re-print the header row after it scrolls off */ | 502 | /* Prepare to re-print the header row after it scrolls off */ |
| 502 | height = 0; | 503 | height = 0; |
| 503 | if (!(opt & OPT_n)) | 504 | if (!(opt & OPT_n)) { |
| 504 | get_terminal_width_height(STDOUT_FILENO, NULL, &height); | 505 | get_terminal_width_height(STDOUT_FILENO, NULL, &height); |
| 506 | /* match 4.0.4 behavior: re-print header if terminal has 4 or more lines */ | ||
| 507 | height -= 3; /* can become zero or negative */ | ||
| 508 | } | ||
| 505 | 509 | ||
| 510 | load_row(G.prev); /* prevents incorrect deltas in 1st sample */ | ||
| 511 | row = 0; | ||
| 506 | /* Main loop */ | 512 | /* Main loop */ |
| 507 | load_row(G.data1); /* prevents incorrect deltas in 1st sample */ | 513 | for (;;) { |
| 508 | for (rows = 0;; rows++) { | 514 | if (row == 0) { |
| 509 | if (rows == 0 || (height > 5 && (rows % (height - 3)) == 0)) | ||
| 510 | print_header(); | 515 | print_header(); |
| 511 | 516 | row = (int)height; | |
| 512 | /* Flip between using data1/2 and data2/1 for old/new */ | ||
| 513 | if (rows & 1) { | ||
| 514 | load_row(G.data1); | ||
| 515 | print_row(G.data1, G.data2); | ||
| 516 | } else { | ||
| 517 | load_row(G.data2); | ||
| 518 | print_row(G.data2, G.data1); | ||
| 519 | } | 517 | } |
| 518 | row--; | ||
| 519 | //if (row < 0) /* height <= 0: -n, or 3 or fewer lines in terminal */ | ||
| 520 | // row = -1; /* do not count down, never become zero */ | ||
| 521 | /* equivalent to above: */ | ||
| 522 | row |= (row >> (sizeof(row)*8 - 1)); | ||
| 523 | |||
| 524 | load_row(G.data); | ||
| 525 | print_row(G.data, G.prev); | ||
| 526 | memcpy(G.prev, G.data, sizeof(G.prev)); | ||
| 520 | 527 | ||
| 521 | if (count > 0 && --count == 0) | 528 | if (count > 0 && --count == 0) |
| 522 | break; | 529 | break; |
