From 52dbac69c27dee67a4c051b1055d93b0ac4e2062 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 13 Apr 2010 13:16:02 -0500 Subject: fix print_size printing fractional gigabyte numbers on 32-bit platforms In print_size(), the math that calculates the fractional remainder of a number used the same integer size as a physical address. However, the "10 *" factor of the algorithm means that a large number (e.g. 1.5GB) can overflow the integer if we're running on a 32-bit system. Therefore, we need to disassociate this function from the size of a physical address. Signed-off-by: Timur Tabi --- lib/display_options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/display_options.c') diff --git a/lib/display_options.c b/lib/display_options.c index 2dc2567410b..08a7914a1d0 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -45,8 +45,8 @@ int display_options (void) */ void print_size (phys_size_t size, const char *s) { - ulong m = 0, n; - phys_size_t d = 1 << 30; /* 1 GB */ + unsigned long m = 0, n; + unsigned long long d = 1 << 30; /* 1 GB */ char c = 'G'; if (size < d) { /* try MB */ -- cgit v1.2.3 From 4b42c9059e165500353174601a8e97b2cf81d3f4 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 13 Apr 2010 13:16:03 -0500 Subject: allow print_size to print large numbers on 32-bit systems Modify print_size() so that it can accept numbers larger than 4GB on 32-bit systems. Add support for display terabyte, petabyte, and exabyte sizes. Change the output to use International Electrotechnical Commission binary prefix standard. Signed-off-by: Timur Tabi --- lib/display_options.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'lib/display_options.c') diff --git a/lib/display_options.c b/lib/display_options.c index 08a7914a1d0..86df05d9e5d 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -39,25 +39,30 @@ int display_options (void) } /* - * print sizes as "xxx kB", "xxx.y kB", "xxx MB", "xxx.y MB", - * xxx GB, or xxx.y GB as needed; allow for optional trailing string + * print sizes as "xxx KiB", "xxx.y KiB", "xxx MiB", "xxx.y MiB", + * xxx GiB, xxx.y GiB, etc as needed; allow for optional trailing string * (like "\n") */ -void print_size (phys_size_t size, const char *s) +void print_size(unsigned long long size, const char *s) { unsigned long m = 0, n; - unsigned long long d = 1 << 30; /* 1 GB */ - char c = 'G'; - - if (size < d) { /* try MB */ - c = 'M'; - d = 1 << 20; - if (size < d) { /* print in kB */ - c = 'k'; - d = 1 << 10; + static const char names[] = {'E', 'P', 'T', 'G', 'M', 'K'}; + unsigned long long d = 1ULL << (10 * ARRAY_SIZE(names)); + char c = 0; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(names); i++, d >>= 10) { + if (size >= d) { + c = names[i]; + break; } } + if (!c) { + printf("%llu Bytes%s", size, s); + return; + } + n = size / d; /* If there's a remainder, deal with it */ @@ -70,11 +75,11 @@ void print_size (phys_size_t size, const char *s) } } - printf ("%2ld", n); + printf ("%lu", n); if (m) { printf (".%ld", m); } - printf (" %cB%s", c, s); + printf (" %ciB%s", c, s); } /* -- cgit v1.2.3 From f2d76ae4fdde180e120ea2d29d6ef881360b3cba Mon Sep 17 00:00:00 2001 From: Nick Thompson Date: Tue, 11 May 2010 11:29:52 +0100 Subject: Avoid use of divides in print_size Modification of print_size to avoid use of divides and especially long long divides. Keep the binary scale factor in terms of bit shifts instead. This should be faster, since the previous code gave the compiler no clues that the divides where always powers of two, preventing optimisation. Signed-off-by: Nick Thompson Acked-by: Timur Tabi --- lib/display_options.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'lib/display_options.c') diff --git a/lib/display_options.c b/lib/display_options.c index 86df05d9e5d..a711425b906 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -46,13 +46,14 @@ int display_options (void) void print_size(unsigned long long size, const char *s) { unsigned long m = 0, n; + unsigned long long f; static const char names[] = {'E', 'P', 'T', 'G', 'M', 'K'}; - unsigned long long d = 1ULL << (10 * ARRAY_SIZE(names)); + unsigned long d = 10 * ARRAY_SIZE(names); char c = 0; unsigned int i; - for (i = 0; i < ARRAY_SIZE(names); i++, d >>= 10) { - if (size >= d) { + for (i = 0; i < ARRAY_SIZE(names); i++, d -= 10) { + if (size >> d) { c = names[i]; break; } @@ -63,11 +64,12 @@ void print_size(unsigned long long size, const char *s) return; } - n = size / d; + n = size >> d; + f = size & ((1ULL << d) - 1); /* If there's a remainder, deal with it */ - if(size % d) { - m = (10 * (size - (n * d)) + (d / 2) ) / d; + if (f) { + m = (10ULL * f + (1ULL << (d - 1))) >> d; if (m >= 10) { m -= 10; -- cgit v1.2.3