free: implement -h

function                                             old     new   delta
.rodata                                           103331  103363     +32
packed_usage                                       33652   33654      +2
free_main                                            657     588     -69
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 34/-69)            Total: -35 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2021-06-18 12:08:02 +02:00
parent 2c436679fb
commit dc30f3dce2
2 changed files with 53 additions and 31 deletions

View File

@ -1065,10 +1065,10 @@ char *smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_
/* If block_size == 0, display size without fractional part, /* If block_size == 0, display size without fractional part,
* else display (size * block_size) with one decimal digit. * else display (size * block_size) with one decimal digit.
* If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...), * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...),
* else divide by display_unit and do not use suffix. */ * else divide by display_unit and do not use suffix.
* Returns "auto pointer" */
#define HUMAN_READABLE_MAX_WIDTH 7 /* "1024.0G" */ #define HUMAN_READABLE_MAX_WIDTH 7 /* "1024.0G" */
#define HUMAN_READABLE_MAX_WIDTH_STR "7" #define HUMAN_READABLE_MAX_WIDTH_STR "7"
//TODO: provide pointer to buf (avoid statics)?
const char *make_human_readable_str(unsigned long long size, const char *make_human_readable_str(unsigned long long size,
unsigned long block_size, unsigned long display_unit) FAST_FUNC; unsigned long block_size, unsigned long display_unit) FAST_FUNC;
/* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */

View File

@ -19,9 +19,9 @@
//kbuild:lib-$(CONFIG_FREE) += free.o //kbuild:lib-$(CONFIG_FREE) += free.o
//usage:#define free_trivial_usage //usage:#define free_trivial_usage
//usage: "" IF_DESKTOP("[-bkmg]") //usage: "" IF_DESKTOP("[-bkmgh]")
//usage:#define free_full_usage "\n\n" //usage:#define free_full_usage "\n\n"
//usage: "Display the amount of free and used system memory" //usage: "Display free and used memory"
//usage: //usage:
//usage:#define free_example_usage //usage:#define free_example_usage
//usage: "$ free\n" //usage: "$ free\n"
@ -29,6 +29,27 @@
//usage: " Mem: 257628 248724 8904 59644 93124\n" //usage: " Mem: 257628 248724 8904 59644 93124\n"
//usage: " Swap: 128516 8404 120112\n" //usage: " Swap: 128516 8404 120112\n"
//usage: "Total: 386144 257128 129016\n" //usage: "Total: 386144 257128 129016\n"
//procps-ng 3.3.15:
// -b, --bytes show output in bytes
// --kilo show output in kilobytes
// --mega show output in megabytes
// --giga show output in gigabytes
// --tera show output in terabytes
// --peta show output in petabytes
// -k, --kibi show output in kibibytes
// -m, --mebi show output in mebibytes
// -g, --gibi show output in gibibytes
// --tebi show output in tebibytes
// --pebi show output in pebibytes
// -h, --human show human-readable output
// --si use powers of 1000 not 1024
// -l, --lohi show detailed low and high memory statistics
// -t, --total show total for RAM + swap
// -s N, --seconds N repeat printing every N seconds
// -c N, --count N repeat printing N times, then exit
// -w, --wide wide output
//
//NB: if we implement -s or -c, need to stop being NOFORK!
#include "libbb.h" #include "libbb.h"
#ifdef __linux__ #ifdef __linux__
@ -38,18 +59,22 @@
struct globals { struct globals {
unsigned mem_unit; unsigned mem_unit;
#if ENABLE_DESKTOP #if ENABLE_DESKTOP
uint8_t unit_steps; unsigned unit;
# define G_unit_steps g->unit_steps # define G_unit g->unit
#else #else
# define G_unit_steps 10 # define G_unit (1 << 10)
#endif #endif
unsigned long cached_kb, available_kb, reclaimable_kb; unsigned long cached_kb, available_kb, reclaimable_kb;
}; };
/* Because of NOFORK, "globals" are not in global data */ /* Because of NOFORK, "globals" are not in global data */
static unsigned long long scale(struct globals *g, unsigned long d) static const char *scale(struct globals *g, unsigned long d)
{ {
return ((unsigned long long)d * g->mem_unit) >> G_unit_steps; /* Display (size * block_size) with one decimal digit.
* If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...),
* else divide by display_unit and do not use suffix.
* Returns "auto pointer" */
return make_human_readable_str(d, g->mem_unit, G_unit);
} }
/* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */ /* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */
@ -88,20 +113,27 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
int seen_available; int seen_available;
#if ENABLE_DESKTOP #if ENABLE_DESKTOP
G.unit_steps = 10; G.unit = 1 << 10;
if (argv[1] && argv[1][0] == '-') { if (argv[1] && argv[1][0] == '-') {
switch (argv[1][1]) { switch (argv[1][1]) {
case 'b': case 'b':
G.unit_steps = 0; G.unit = 1;
break; break;
case 'k': /* 2^10 */ case 'k': /* 2^10 */
/* G.unit_steps = 10; - already is */ /* G.unit = 1 << 10; - already is */
break; break;
case 'm': /* 2^20 */ case 'm': /* 2^20 */
G.unit_steps = 20; G.unit = 1 << 20;
break; break;
case 'g': /* 2^30 */ case 'g': /* 2^30 */
G.unit_steps = 30; G.unit = 1 << 30;
break;
// case 't':
// -- WRONG, -t is not "terabytes" in procps-ng, it's --total
// G.unit = 1 << 40;
// break;
case 'h':
G.unit = 0; /* human readable */
break; break;
default: default:
bb_show_usage(); bb_show_usage();
@ -126,23 +158,13 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit; cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit;
cached_plus_free = cached + info.freeram; cached_plus_free = cached + info.freeram;
/* In case (long long * G.mem_unit) can overflow, this can be used to reduce the chances */ printf("%12s%12s%12s",
#if 0 //ENABLE_DESKTOP
while (!(G.mem_unit & 1) && G.unit_steps != 0) {
G.mem_unit >>= 1;
G.unit_steps--;
//bb_error_msg("mem_unit:%d unit_steps:%d", G.mem_unit, G.unit_steps);
}
#endif
#define FIELDS_6 "%12llu %11llu %11llu %11llu %11llu %11llu\n"
#define FIELDS_3 (FIELDS_6 + 6 + 7 + 7)
#define FIELDS_2 (FIELDS_6 + 6 + 7 + 7 + 7)
printf(FIELDS_6,
scale(&G, info.totalram), //total scale(&G, info.totalram), //total
scale(&G, info.totalram - cached_plus_free), //used scale(&G, info.totalram - cached_plus_free), //used
scale(&G, info.freeram), //free scale(&G, info.freeram) //free
);
/* using two printf's: only 4 auto strings are supported, we need 6 */
printf("%12s%12s%12s\n",
scale(&G, info.sharedram), //shared scale(&G, info.sharedram), //shared
scale(&G, cached), //buff/cache scale(&G, cached), //buff/cache
scale(&G, available) //available scale(&G, available) //available
@ -152,14 +174,14 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
* buffer cache as free memory. */ * buffer cache as free memory. */
if (!seen_available) { if (!seen_available) {
printf("-/+ buffers/cache: "); printf("-/+ buffers/cache: ");
printf(FIELDS_2, printf("%12s%12s%12s\n" + 4,
scale(&G, info.totalram - cached_plus_free), //used scale(&G, info.totalram - cached_plus_free), //used
scale(&G, cached_plus_free) //free scale(&G, cached_plus_free) //free
); );
} }
#if BB_MMU #if BB_MMU
printf("Swap: "); printf("Swap: ");
printf(FIELDS_3, printf("%12s%12s%12s\n",
scale(&G, info.totalswap), //total scale(&G, info.totalswap), //total
scale(&G, info.totalswap - info.freeswap), //used scale(&G, info.totalswap - info.freeswap), //used
scale(&G, info.freeswap) //free scale(&G, info.freeswap) //free