free: Use IEC units

Free always used 1024 based units but used the confusing old style
kilo,mega etc.

This change changes the names to kibi,mebi for 1024 based divisors
and kilo,mega for 1000 based divisors or IEC units.

It also checks if you try to set two units, e.g free -k -m
Petabyte and Pebibyte have been added.

If you used to use the long options such as --mega these will now
actually print megabytes (they previously printed mebibytes).
The short options are being used on the IEC units

References: https://www.gitorious.org/procps/procps/merge_requests/38

Signed-off-by: Craig Small <csmall@enc.com.au>
This commit is contained in:
Craig Small 2015-04-03 19:18:58 +11:00
parent 6ed8cf3444
commit f8e98b65ae
3 changed files with 109 additions and 28 deletions

50
free.1
View File

@ -2,7 +2,7 @@
.\" This page Copyright (C) 1993 Matt Welsh, mdw@sunsite.unc.edu.
.\" Long options where added at April 15th, 2011.
.\" Freely distributable under the terms of the GPL
.TH FREE 1 "July 2014" "procps-ng" "User Commands"
.TH FREE 1 "Apr 2015" "procps-ng" "User Commands"
.SH NAME
free \- Display amount of free and used memory in the system
.SH SYNOPSIS
@ -50,17 +50,35 @@ kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as \fBfree\fR)
\fB\-b\fR, \fB\-\-bytes\fR
Display the amount of memory in bytes.
.TP
\fB\-k\fR, \fB\-\-kilo\fR
Display the amount of memory in kilobytes. This is the default.
\fB\-k\fR, \fB\-\-kibi\fR
Display the amount of memory in kibibytes. This is the default.
.TP
\fB\-m\fR, \fB\-\-mega\fR
Display the amount of memory in megabytes.
\fB\-m\fR, \fB\-\-mebi\fR
Display the amount of memory in mebibytes.
.TP
\fB\-g\fR, \fB\-\-giga\fR
Display the amount of memory in gigabytes.
\fB\-g\fR, \fB\-\-gibi\fR
Display the amount of memory in gibibytes.
.TP
\fB\-\-tebi\fR
Display the amount of memory in tebibytes.
.TP
\fB\-\-pebi\fR
Display the amount of memory in pebibytes.
.TP
\fB\-\-kilo\fR
Display the amount of memory in kilobytes. Implies --si.
.TP
\fB\-\-mega\fR
Display the amount of memory in megabytes. Implies --si.
.TP
\fB\-\-giga\fR
Display the amount of memory in gigabytes. Implies --si.
.TP
\fB\-\-tera\fR
Display the amount of memory in terabytes.
Display the amount of memory in terabytes. Implies --si.
.TP
\fB\-\-peta\fR
Display the amount of memory in petabytes. Implies --si.
.TP
\fB\-h\fR, \fB\-\-human\fP
Show all output fields automatically scaled to shortest three digit unit and
@ -68,14 +86,15 @@ display the units of print out. Following units are used.
.sp
.nf
B = bytes
K = kilos
M = megas
G = gigas
T = teras
K = kibibyte
M = mebibyte
G = gibibyte
T = tebibyte
P = pebibyte
.fi
.sp
If unit is missing, and you have petabyte of RAM or swap, the number is in
terabytes and columns might not be aligned with header.
If unit is missing, and you have exbibyte of RAM or swap, the number is in
tebibytes and columns might not be aligned with header.
.TP
\fB\-w\fR, \fB\-\-wide\fR
Switch to the wide mode. The wide mode produces lines longer
@ -101,7 +120,8 @@ apart. You may actually specify any floating point number for
is used for microsecond resolution delay times.
.TP
\fB\-\-si\fR
Use power of 1000 not 1024.
Use kilo, mega, giga etc (power of 1000) instead of kibi, mebi, gibi (power
of 1024).
.TP
\fB\-t\fR, \fB\-\-total\fR
Display a line showing the column totals.

85
free.c
View File

@ -74,10 +74,16 @@ static void __attribute__ ((__noreturn__))
_(" %s [options]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out);
fputs(_(" -b, --bytes show output in bytes\n"), out);
fputs(_(" -k, --kilo show output in kilobytes\n"), out);
fputs(_(" -m, --mega show output in megabytes\n"), out);
fputs(_(" -g, --giga show output in gigabytes\n"), out);
fputs(_(" --kilo show output in kilobytes\n"), out);
fputs(_(" --mega show output in megabytes\n"), out);
fputs(_(" --giga show output in gigabytes\n"), out);
fputs(_(" --tera show output in terabytes\n"), out);
fputs(_(" --peta show output in petabytes\n"), out);
fputs(_(" -k, --kibi show output in kibibytes\n"), out);
fputs(_(" -m, --mebi show output in mebibytes\n"), out);
fputs(_(" -g, --gibi show output in gibibytes\n"), out);
fputs(_(" --tebi show output in tebibytes\n"), out);
fputs(_(" --pebi show output in pebibytes\n"), out);
fputs(_(" -h, --human show human-readable output\n"), out);
fputs(_(" --si use powers of 1000 not 1024\n"), out);
fputs(_(" -l, --lohi show detailed low and high memory statistics\n"), out);
@ -101,7 +107,7 @@ double power(unsigned int base, unsigned int expo)
/* idea of this function is copied from top size scaling */
static const char *scale_size(unsigned long size, int flags, struct commandline_arguments args)
{
static char nextup[] = { 'B', 'K', 'M', 'G', 'T', 0 };
static char nextup[] = { 'B', 'K', 'M', 'G', 'T', 'P', 0 };
static char buf[BUFSIZ];
int i;
char *up;
@ -163,6 +169,7 @@ static const char *scale_size(unsigned long size, int flags, struct commandline_
case 3:
case 4:
case 5:
case 6:
if (4 >=
snprintf(buf, sizeof(buf), "%.1f%c",
(float)(size / power(base, i - 2)), *up))
@ -172,21 +179,29 @@ static const char *scale_size(unsigned long size, int flags, struct commandline_
(long)(size / power(base, i - 2)), *up))
return buf;
break;
case 6:
case 7:
break;
}
}
/*
* On system where there is more than petabyte of memory or swap the
* On system where there is more than exbibyte of memory or swap the
* output does not fit to column. For incoming few years this should
* not be a big problem (wrote at Apr, 2011).
* not be a big problem (wrote at Apr, 2015).
*/
return buf;
}
static void check_unit_set(int *unit_set)
{
if (*unit_set)
xerrx(EXIT_FAILURE,
_("Multiple unit options doesn't make sense."));
*unit_set = 1;
}
int main(int argc, char **argv)
{
int c, flags = 0;
int c, flags = 0, unit_set = 0;
char *endptr;
struct commandline_arguments args;
@ -196,16 +211,28 @@ int main(int argc, char **argv)
*/
enum {
SI_OPTION = CHAR_MAX + 1,
KILO_OPTION,
MEGA_OPTION,
GIGA_OPTION,
TERA_OPTION,
PETA_OPTION,
TEBI_OPTION,
PEBI_OPTION,
HELP_OPTION
};
static const struct option longopts[] = {
{ "bytes", no_argument, NULL, 'b' },
{ "kilo", no_argument, NULL, 'k' },
{ "mega", no_argument, NULL, 'm' },
{ "giga", no_argument, NULL, 'g' },
{ "kilo", no_argument, NULL, KILO_OPTION },
{ "mega", no_argument, NULL, MEGA_OPTION },
{ "giga", no_argument, NULL, GIGA_OPTION },
{ "tera", no_argument, NULL, TERA_OPTION },
{ "peta", no_argument, NULL, PETA_OPTION },
{ "kibi", no_argument, NULL, 'k' },
{ "mebi", no_argument, NULL, 'm' },
{ "gibi", no_argument, NULL, 'g' },
{ "tebi", no_argument, NULL, TEBI_OPTION },
{ "pebi", no_argument, NULL, PEBI_OPTION },
{ "human", no_argument, NULL, 'h' },
{ "si", no_argument, NULL, SI_OPTION },
{ "lohi", no_argument, NULL, 'l' },
@ -234,20 +261,54 @@ int main(int argc, char **argv)
while ((c = getopt_long(argc, argv, "bkmghltc:ws:V", longopts, NULL)) != -1)
switch (c) {
case 'b':
check_unit_set(&unit_set);
args.exponent = 1;
break;
case 'k':
check_unit_set(&unit_set);
args.exponent = 2;
break;
case 'm':
check_unit_set(&unit_set);
args.exponent = 3;
break;
case 'g':
check_unit_set(&unit_set);
args.exponent = 4;
break;
case TERA_OPTION:
case TEBI_OPTION:
check_unit_set(&unit_set);
args.exponent = 5;
break;
case PEBI_OPTION:
check_unit_set(&unit_set);
args.exponent = 6;
break;
case KILO_OPTION:
check_unit_set(&unit_set);
args.exponent = 2;
flags |= FREE_SI;
break;
case MEGA_OPTION:
check_unit_set(&unit_set);
args.exponent = 3;
flags |= FREE_SI;
break;
case GIGA_OPTION:
check_unit_set(&unit_set);
args.exponent = 4;
flags |= FREE_SI;
break;
case TERA_OPTION:
check_unit_set(&unit_set);
args.exponent = 5;
flags |= FREE_SI;
break;
case PETA_OPTION:
check_unit_set(&unit_set);
args.exponent = 6;
flags |= FREE_SI;
break;
case 'h':
flags |= FREE_HUMANREADABLE;
break;

View File

@ -19,7 +19,7 @@ set swaptotal [ expr { $swaptotal_kb * 1024 } ]
spawn $free -b
expect_pass "$test" "^${free_header}Mem:\\s+${memtotal}\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s*Swap:\\s+${swaptotal}\\s+\\d+\\s+\\d+\\s*"
foreach {arg divisor } {-k 1 -m 1024 -g 1048576 } {
foreach {arg divisor } {-k 1 -m 1024 -g 1048576 --mega 1000 --giga 1000000 } {
set test "free with $arg argument"
set memtotal [ expr { $memtotal_kb / $divisor } ]
set swaptotal [ expr { $swaptotal_kb / $divisor } ]