All of lore.kernel.org
 help / color / mirror / Atom feed
From: James Bottomley <James.Bottomley-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
To: "Elliott,
	Robert (Persistent Memory)"
	<elliott-ZPxbGqLxI0U@public.gmane.org>,
	Andy Shevchenko
	<andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
	Matt Fleming
	<matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>,
	Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>,
	Ingo Molnar <mingo-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	"H . Peter Anvin" <hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>,
	"linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org"
	<linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Rasmus Villemoes
	<linux-qQsb+v5E8BnlAoU/VqSP6n9LOBIZ5rWg@public.gmane.org>,
	Andrew Morton
	<akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>,
	"linux-kernel @ vger . kernel . org"
	<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH v3 3/4] x86/efi: print size in binary units in efi_print_memmap
Date: Mon, 25 Jan 2016 10:56:12 -0800	[thread overview]
Message-ID: <1453748172.2363.36.camel@HansenPartnership.com> (raw)
In-Reply-To: <94D0CD8314A33A4D9D801C0FE68B40295BF3B840-W1gbDvblbosSZAcGdq5asR6epYMZPwEe5NbjCUgZEJk@public.gmane.org>

On Mon, 2016-01-25 at 18:02 +0000, Elliott, Robert (Persistent Memory)
wrote:
> 
> 
> > -----Original Message-----
> > From: James Bottomley [mailto:James.Bottomley-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org
> > ]
> > Sent: Saturday, January 23, 2016 10:44 AM
> > To: Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>; Matt
> > Fleming
> > <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>; Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>;
> > Ingo
> > Molnar <mingo-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>; H . Peter Anvin <hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>; linux-
> > efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Rasmus Villemoes <linux-qQsb+v5E8BnlAoU/VqSP6n9LOBIZ5rWg@public.gmane.org>;
> > Andrew
> > Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>; linux-kernel @ vger . kernel .
> > org
> > <linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
> > Cc: Elliott, Robert (Persistent Memory) <elliott-ZPxbGqLxI0U@public.gmane.org>
> > Subject: Re: [PATCH v3 3/4] x86/efi: print size in binary units in
> > efi_print_memmap
> > 
> > On Sat, 2016-01-23 at 16:55 +0200, Andy Shevchenko wrote:
> > > From: Robert Elliott <elliott-ZPxbGqLxI0U@public.gmane.org>
> > > 
> > > Print the size in the best-fit B, KiB, MiB, etc. units rather
> > > than
> > > always MiB. This avoids rounding, which can be misleading.
> > > 
> 
> ...
> > 
> > What if size is zero, which might happen on a UEFI screw up?  
> 
> > Also it gives really odd results for non power of two memory sizes.
> > 16384MB prints as 16GiB but 16385 prints as 16385MiB.
> > If the goal is to have a clean interface reporting only the first
> > four
> > significant figures and a size exponent, then a helper would be
> > much
> > better than trying to open code this ad hoc.
> 
> An impetus for the patch was to stop rounding the sub-MiB values,
> which is misleading and can hide bugs.  For my systems, the
> minimum size of a range happens to be 4 KiB, so I wanted at least
> that resolution. However, I don't want to print everything as KiB,
> because that makes big sizes less clear.
> 
> Example - old output:
> efi: mem00: [Conventional Memory...] range=[0x0000000000000000
> -0x0000000000001000) (0MB)
> efi: mem01: [Loader Data        ...] range=[0x0000000000001000
> -0x0000000000002000) (0MB)
> efi: mem02: [Conventional Memory...] range=[0x0000000000002000
> -0x0000000000093000) (0MB)
> efi: mem03: [Reserved           ...] range=[0x0000000000093000
> -0x0000000000094000) (0MB)
> 
> Proposed output:
> efi: mem00: [Conventional Memory...] range=[0x0000000000000000
> -0x0000000000092fff] (588 KiB @ 0 B)
> efi: mem01: [Reserved           ...] range=[0x0000000000093000
> -0x0000000000093fff] (4 KiB @ 588 KiB)
> efi: mem02: [Conventional Memory...] range=[0x0000000000094000
> -0x000000000009ffff] (48 KiB @ 592 KiB)
> efi: mem03: [Loader Data        ...] range=[0x0000000000100000
> -0x00000000013e8fff] (19364 KiB @ 1 MiB)
> (notes:
>  - from a different system
>  - including both base and size
>  - Matt didn't like printing the base so that's been removed)
> 
> With persistent memory (NVDIMMs) bringing storage device capacities
> into the memory subsystem, MiB is too small.  Seeing a 1 TiB NVDIMM
> as 1 TiB is a lot clearer than having to recognize 1048576 MiB as
> the same value (especially since these power-of-two quantities
> don't just chop off zeros on the right).
> 
> Examples:
> efi: mem50: [Runtime Data       ...] range=[0x00000000784ff000
> -0x00000000788fefff] (4 MiB @ 1971196 KiB)
> efi: mem56: [Conventional Memory...] range=[0x0000000100000000
> -0x000000087fffffff] (30 GiB @ 4 GiB)
> efi: mem58: [Memory Mapped I/O  ...] range=[0x0000000080000000
> -0x000000008fffffff] (256 MiB @ 2 GiB)
> efi: mem60: [Persistent Memory  ...] range=[0x0000001480000000
> -0x0000001a7fffffff] (24 GiB @ 82 GiB)

OK, this is getting a bit out of hand: I didn't say your aim was bad
... I think it's a reasonable desire; I said the proposed
implementation was bad.  Using ffs leads to precision runaway and
exporting an array from string_helpers.c is simply the wrong way to do
it.

Since we've now spent more time arguing about this than it would take
to do a correct patch, this is what I was thinking.  It extracts the
precision reduction core from string_helpers.c and exposes it to all
users who want to convert to units.  I added a nozeros option becuase I
think you want it to print 1 GiB rather than 1.00 GiB for exact powers
of two.  (OK, and I fixed a bug where it will report small amounts as
1.00 B instead of whole number of bytes).  Absent the nozero option,
you could simply have used string_get_size(), with a block size of 1.

James

---

diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
index dabe643..78935fae 100644
--- a/include/linux/string_helpers.h
+++ b/include/linux/string_helpers.h
@@ -10,6 +10,8 @@ enum string_size_units {
 	STRING_UNITS_2,		/* use binary powers of 2^10 */
 };
 
+void string_get_units(u64 size, const enum string_size_units units,
+		      char *buf, int len, bool nozeros);
 void string_get_size(u64 size, u64 blk_size, enum string_size_units units,
 		     char *buf, int len);
 
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 5c88204..ab6b332 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -13,21 +13,13 @@
 #include <linux/string.h>
 #include <linux/string_helpers.h>
 
-/**
- * string_get_size - get the size in the specified units
- * @size:	The size to be converted in blocks
- * @blk_size:	Size of the block (use 1 for size in bytes)
- * @units:	units to use (powers of 1000 or 1024)
- * @buf:	buffer to format to
- * @len:	length of buffer
- *
- * This function returns a string formatted to 3 significant figures
- * giving the size in the required units.  @buf should have room for
- * at least 9 bytes and will always be zero terminated.
- *
- */
-void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
-		     char *buf, int len)
+static const unsigned int divisor[] = {
+	[STRING_UNITS_10] = 1000,
+	[STRING_UNITS_2] = 1024,
+};
+
+static void string_reduce(u64 size, int log, const enum string_size_units units,
+			  char *buf, int len, bool nozeros)
 {
 	static const char *const units_10[] = {
 		"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
@@ -39,52 +31,23 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		[STRING_UNITS_10] = units_10,
 		[STRING_UNITS_2] = units_2,
 	};
-	static const unsigned int divisor[] = {
-		[STRING_UNITS_10] = 1000,
-		[STRING_UNITS_2] = 1024,
-	};
 	static const unsigned int rounding[] = { 500, 50, 5 };
-	int i = 0, j;
-	u32 remainder = 0, sf_cap;
+	char zeros[] = ".00";
+
+	int j;
+	u32 sf_cap, remainder = 0;
 	char tmp[8];
 	const char *unit;
 
 	tmp[0] = '\0';
 
-	if (blk_size == 0)
-		size = 0;
 	if (size == 0)
 		goto out;
 
-	/* This is Napier's algorithm.  Reduce the original block size to
-	 *
-	 * coefficient * divisor[units]^i
-	 *
-	 * we do the reduction so both coefficients are just under 32 bits so
-	 * that multiplying them together won't overflow 64 bits and we keep
-	 * as much precision as possible in the numbers.
-	 *
-	 * Note: it's safe to throw away the remainders here because all the
-	 * precision is in the coefficients.
-	 */
-	while (blk_size >> 32) {
-		do_div(blk_size, divisor[units]);
-		i++;
-	}
-
-	while (size >> 32) {
-		do_div(size, divisor[units]);
-		i++;
-	}
-
-	/* now perform the actual multiplication keeping i as the sum of the
-	 * two logarithms */
-	size *= blk_size;
-
-	/* and logarithmically reduce it until it's just under the divisor */
+	/* Logarithmically reduce it until it's just under the divisor */
 	while (size >= divisor[units]) {
 		remainder = do_div(size, divisor[units]);
-		i++;
+		log++;
 	}
 
 	/* work out in j how many digits of precision we need from the
@@ -109,21 +72,93 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		size += 1;
 	}
 
-	if (j) {
+	if (j && log) {
 		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
 		tmp[j+1] = '\0';
+		zeros[j+1] = '\0';
+		if (nozeros && strcmp(tmp, zeros) == 0)
+			tmp[0]='\0';
 	}
 
  out:
-	if (i >= ARRAY_SIZE(units_2))
+	if (log >= ARRAY_SIZE(units_2))
 		unit = "UNK";
 	else
-		unit = units_str[units][i];
+		unit = units_str[units][log];
 
 	snprintf(buf, len, "%u%s %s", (u32)size,
 		 tmp, unit);
 }
-EXPORT_SYMBOL(string_get_size);
+
+/**
+ * string_get_units - convert size to specified units
+ * @size:	The quantity to be converted
+ * @units:	units to use (powers of 1000 or 1024)
+ * @buf:	buffer to format to
+ * @len:	length of buffer
+ * @nozereos:	eliminate zeros after the decimal point if true
+ *
+ * This function returns a string formatted to 3 significant figures
+ * giving the size in the required units.  @buf should have room for
+ * at least 9 bytes and will always be zero terminated.
+ */
+void string_get_units(u64 size, const enum string_size_units units,
+		      char *buf, int len, bool nozeros)
+{
+	string_reduce(size, 0, units, buf, len, nozeros);
+}
+
+/**
+ * string_get_size - get the size in the specified units
+ * @size:	The size to be converted in blocks
+ * @blk_size:	Size of the block (use 1 for size in bytes)
+ * @units:	units to use (powers of 1000 or 1024)
+ * @buf:	buffer to format to
+ * @len:	length of buffer
+ *
+ * This function returns a string formatted to 3 significant figures
+ * giving the size in the required units.  @buf should have room for
+ * at least 9 bytes and will always be zero terminated.
+ *
+ */
+void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
+		     char *buf, int len)
+{
+	int i = 0;
+
+	if (blk_size == 0)
+		size = 0;
+	if (size == 0)
+		goto out;
+
+	/* This is Napier's algorithm.  Reduce the original block size to
+	 *
+	 * coefficient * divisor[units]^i
+	 *
+	 * we do the reduction so both coefficients are just under 32 bits so
+	 * that multiplying them together won't overflow 64 bits and we keep
+	 * as much precision as possible in the numbers.
+	 *
+	 * Note: it's safe to throw away the remainders here because all the
+	 * precision is in the coefficients.
+	 */
+	while (blk_size >> 32) {
+		do_div(blk_size, divisor[units]);
+		i++;
+	}
+
+	while (size >> 32) {
+		do_div(size, divisor[units]);
+		i++;
+	}
+
+	/* now perform the actual multiplication keeping i as the sum of the
+	 * two logarithms */
+	size *= blk_size;
+
+ out:
+	string_reduce(size, i, units, buf, len, false);
+}
 
 static bool unescape_space(char **src, char **dst)
 {

WARNING: multiple messages have this Message-ID (diff)
From: James Bottomley <James.Bottomley@HansenPartnership.com>
To: "Elliott, Robert (Persistent Memory)" <elliott@hpe.com>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Matt Fleming <matt@codeblueprint.co.uk>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, "H . Peter Anvin" <hpa@zytor.com>,
	"linux-efi@vger.kernel.org" <linux-efi@vger.kernel.org>,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Andrew Morton <akpm@linux-foundation.org>,
	"linux-kernel @ vger . kernel . org"
	<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v3 3/4] x86/efi: print size in binary units in efi_print_memmap
Date: Mon, 25 Jan 2016 10:56:12 -0800	[thread overview]
Message-ID: <1453748172.2363.36.camel@HansenPartnership.com> (raw)
In-Reply-To: <94D0CD8314A33A4D9D801C0FE68B40295BF3B840@G9W0745.americas.hpqcorp.net>

On Mon, 2016-01-25 at 18:02 +0000, Elliott, Robert (Persistent Memory)
wrote:
> 
> 
> > -----Original Message-----
> > From: James Bottomley [mailto:James.Bottomley@HansenPartnership.com
> > ]
> > Sent: Saturday, January 23, 2016 10:44 AM
> > To: Andy Shevchenko <andriy.shevchenko@linux.intel.com>; Matt
> > Fleming
> > <matt@codeblueprint.co.uk>; Thomas Gleixner <tglx@linutronix.de>;
> > Ingo
> > Molnar <mingo@redhat.com>; H . Peter Anvin <hpa@zytor.com>; linux-
> > efi@vger.kernel.org; Rasmus Villemoes <linux@rasmusvillemoes.dk>;
> > Andrew
> > Morton <akpm@linux-foundation.org>; linux-kernel @ vger . kernel .
> > org
> > <linux-kernel@vger.kernel.org>
> > Cc: Elliott, Robert (Persistent Memory) <elliott@hpe.com>
> > Subject: Re: [PATCH v3 3/4] x86/efi: print size in binary units in
> > efi_print_memmap
> > 
> > On Sat, 2016-01-23 at 16:55 +0200, Andy Shevchenko wrote:
> > > From: Robert Elliott <elliott@hpe.com>
> > > 
> > > Print the size in the best-fit B, KiB, MiB, etc. units rather
> > > than
> > > always MiB. This avoids rounding, which can be misleading.
> > > 
> 
> ...
> > 
> > What if size is zero, which might happen on a UEFI screw up?  
> 
> > Also it gives really odd results for non power of two memory sizes.
> > 16384MB prints as 16GiB but 16385 prints as 16385MiB.
> > If the goal is to have a clean interface reporting only the first
> > four
> > significant figures and a size exponent, then a helper would be
> > much
> > better than trying to open code this ad hoc.
> 
> An impetus for the patch was to stop rounding the sub-MiB values,
> which is misleading and can hide bugs.  For my systems, the
> minimum size of a range happens to be 4 KiB, so I wanted at least
> that resolution. However, I don't want to print everything as KiB,
> because that makes big sizes less clear.
> 
> Example - old output:
> efi: mem00: [Conventional Memory...] range=[0x0000000000000000
> -0x0000000000001000) (0MB)
> efi: mem01: [Loader Data        ...] range=[0x0000000000001000
> -0x0000000000002000) (0MB)
> efi: mem02: [Conventional Memory...] range=[0x0000000000002000
> -0x0000000000093000) (0MB)
> efi: mem03: [Reserved           ...] range=[0x0000000000093000
> -0x0000000000094000) (0MB)
> 
> Proposed output:
> efi: mem00: [Conventional Memory...] range=[0x0000000000000000
> -0x0000000000092fff] (588 KiB @ 0 B)
> efi: mem01: [Reserved           ...] range=[0x0000000000093000
> -0x0000000000093fff] (4 KiB @ 588 KiB)
> efi: mem02: [Conventional Memory...] range=[0x0000000000094000
> -0x000000000009ffff] (48 KiB @ 592 KiB)
> efi: mem03: [Loader Data        ...] range=[0x0000000000100000
> -0x00000000013e8fff] (19364 KiB @ 1 MiB)
> (notes:
>  - from a different system
>  - including both base and size
>  - Matt didn't like printing the base so that's been removed)
> 
> With persistent memory (NVDIMMs) bringing storage device capacities
> into the memory subsystem, MiB is too small.  Seeing a 1 TiB NVDIMM
> as 1 TiB is a lot clearer than having to recognize 1048576 MiB as
> the same value (especially since these power-of-two quantities
> don't just chop off zeros on the right).
> 
> Examples:
> efi: mem50: [Runtime Data       ...] range=[0x00000000784ff000
> -0x00000000788fefff] (4 MiB @ 1971196 KiB)
> efi: mem56: [Conventional Memory...] range=[0x0000000100000000
> -0x000000087fffffff] (30 GiB @ 4 GiB)
> efi: mem58: [Memory Mapped I/O  ...] range=[0x0000000080000000
> -0x000000008fffffff] (256 MiB @ 2 GiB)
> efi: mem60: [Persistent Memory  ...] range=[0x0000001480000000
> -0x0000001a7fffffff] (24 GiB @ 82 GiB)

OK, this is getting a bit out of hand: I didn't say your aim was bad
... I think it's a reasonable desire; I said the proposed
implementation was bad.  Using ffs leads to precision runaway and
exporting an array from string_helpers.c is simply the wrong way to do
it.

Since we've now spent more time arguing about this than it would take
to do a correct patch, this is what I was thinking.  It extracts the
precision reduction core from string_helpers.c and exposes it to all
users who want to convert to units.  I added a nozeros option becuase I
think you want it to print 1 GiB rather than 1.00 GiB for exact powers
of two.  (OK, and I fixed a bug where it will report small amounts as
1.00 B instead of whole number of bytes).  Absent the nozero option,
you could simply have used string_get_size(), with a block size of 1.

James

---

diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
index dabe643..78935fae 100644
--- a/include/linux/string_helpers.h
+++ b/include/linux/string_helpers.h
@@ -10,6 +10,8 @@ enum string_size_units {
 	STRING_UNITS_2,		/* use binary powers of 2^10 */
 };
 
+void string_get_units(u64 size, const enum string_size_units units,
+		      char *buf, int len, bool nozeros);
 void string_get_size(u64 size, u64 blk_size, enum string_size_units units,
 		     char *buf, int len);
 
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 5c88204..ab6b332 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -13,21 +13,13 @@
 #include <linux/string.h>
 #include <linux/string_helpers.h>
 
-/**
- * string_get_size - get the size in the specified units
- * @size:	The size to be converted in blocks
- * @blk_size:	Size of the block (use 1 for size in bytes)
- * @units:	units to use (powers of 1000 or 1024)
- * @buf:	buffer to format to
- * @len:	length of buffer
- *
- * This function returns a string formatted to 3 significant figures
- * giving the size in the required units.  @buf should have room for
- * at least 9 bytes and will always be zero terminated.
- *
- */
-void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
-		     char *buf, int len)
+static const unsigned int divisor[] = {
+	[STRING_UNITS_10] = 1000,
+	[STRING_UNITS_2] = 1024,
+};
+
+static void string_reduce(u64 size, int log, const enum string_size_units units,
+			  char *buf, int len, bool nozeros)
 {
 	static const char *const units_10[] = {
 		"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
@@ -39,52 +31,23 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		[STRING_UNITS_10] = units_10,
 		[STRING_UNITS_2] = units_2,
 	};
-	static const unsigned int divisor[] = {
-		[STRING_UNITS_10] = 1000,
-		[STRING_UNITS_2] = 1024,
-	};
 	static const unsigned int rounding[] = { 500, 50, 5 };
-	int i = 0, j;
-	u32 remainder = 0, sf_cap;
+	char zeros[] = ".00";
+
+	int j;
+	u32 sf_cap, remainder = 0;
 	char tmp[8];
 	const char *unit;
 
 	tmp[0] = '\0';
 
-	if (blk_size == 0)
-		size = 0;
 	if (size == 0)
 		goto out;
 
-	/* This is Napier's algorithm.  Reduce the original block size to
-	 *
-	 * coefficient * divisor[units]^i
-	 *
-	 * we do the reduction so both coefficients are just under 32 bits so
-	 * that multiplying them together won't overflow 64 bits and we keep
-	 * as much precision as possible in the numbers.
-	 *
-	 * Note: it's safe to throw away the remainders here because all the
-	 * precision is in the coefficients.
-	 */
-	while (blk_size >> 32) {
-		do_div(blk_size, divisor[units]);
-		i++;
-	}
-
-	while (size >> 32) {
-		do_div(size, divisor[units]);
-		i++;
-	}
-
-	/* now perform the actual multiplication keeping i as the sum of the
-	 * two logarithms */
-	size *= blk_size;
-
-	/* and logarithmically reduce it until it's just under the divisor */
+	/* Logarithmically reduce it until it's just under the divisor */
 	while (size >= divisor[units]) {
 		remainder = do_div(size, divisor[units]);
-		i++;
+		log++;
 	}
 
 	/* work out in j how many digits of precision we need from the
@@ -109,21 +72,93 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		size += 1;
 	}
 
-	if (j) {
+	if (j && log) {
 		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
 		tmp[j+1] = '\0';
+		zeros[j+1] = '\0';
+		if (nozeros && strcmp(tmp, zeros) == 0)
+			tmp[0]='\0';
 	}
 
  out:
-	if (i >= ARRAY_SIZE(units_2))
+	if (log >= ARRAY_SIZE(units_2))
 		unit = "UNK";
 	else
-		unit = units_str[units][i];
+		unit = units_str[units][log];
 
 	snprintf(buf, len, "%u%s %s", (u32)size,
 		 tmp, unit);
 }
-EXPORT_SYMBOL(string_get_size);
+
+/**
+ * string_get_units - convert size to specified units
+ * @size:	The quantity to be converted
+ * @units:	units to use (powers of 1000 or 1024)
+ * @buf:	buffer to format to
+ * @len:	length of buffer
+ * @nozereos:	eliminate zeros after the decimal point if true
+ *
+ * This function returns a string formatted to 3 significant figures
+ * giving the size in the required units.  @buf should have room for
+ * at least 9 bytes and will always be zero terminated.
+ */
+void string_get_units(u64 size, const enum string_size_units units,
+		      char *buf, int len, bool nozeros)
+{
+	string_reduce(size, 0, units, buf, len, nozeros);
+}
+
+/**
+ * string_get_size - get the size in the specified units
+ * @size:	The size to be converted in blocks
+ * @blk_size:	Size of the block (use 1 for size in bytes)
+ * @units:	units to use (powers of 1000 or 1024)
+ * @buf:	buffer to format to
+ * @len:	length of buffer
+ *
+ * This function returns a string formatted to 3 significant figures
+ * giving the size in the required units.  @buf should have room for
+ * at least 9 bytes and will always be zero terminated.
+ *
+ */
+void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
+		     char *buf, int len)
+{
+	int i = 0;
+
+	if (blk_size == 0)
+		size = 0;
+	if (size == 0)
+		goto out;
+
+	/* This is Napier's algorithm.  Reduce the original block size to
+	 *
+	 * coefficient * divisor[units]^i
+	 *
+	 * we do the reduction so both coefficients are just under 32 bits so
+	 * that multiplying them together won't overflow 64 bits and we keep
+	 * as much precision as possible in the numbers.
+	 *
+	 * Note: it's safe to throw away the remainders here because all the
+	 * precision is in the coefficients.
+	 */
+	while (blk_size >> 32) {
+		do_div(blk_size, divisor[units]);
+		i++;
+	}
+
+	while (size >> 32) {
+		do_div(size, divisor[units]);
+		i++;
+	}
+
+	/* now perform the actual multiplication keeping i as the sum of the
+	 * two logarithms */
+	size *= blk_size;
+
+ out:
+	string_reduce(size, i, units, buf, len, false);
+}
 
 static bool unescape_space(char **src, char **dst)
 {

  parent reply	other threads:[~2016-01-25 18:56 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-23 14:55 [PATCH v3 0/4] x86/efi: use binary units when printing Andy Shevchenko
2016-01-23 14:55 ` [PATCH v3 1/4] lib/string_helpers: export string_units_{2,10} for others Andy Shevchenko
     [not found]   ` <1453560913-134672-2-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2016-01-23 16:14     ` James Bottomley
2016-01-23 16:14       ` James Bottomley
     [not found]       ` <1453565662.2470.5.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-01-23 16:58         ` Andy Shevchenko
2016-01-23 16:58           ` Andy Shevchenko
2016-01-23 14:55 ` [PATCH v3 2/4] lib/string_helpers: fix indentation in few places Andy Shevchenko
2016-01-23 14:55 ` [PATCH v3 3/4] x86/efi: print size in binary units in efi_print_memmap Andy Shevchenko
     [not found]   ` <1453560913-134672-4-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2016-01-23 16:44     ` James Bottomley
2016-01-23 16:44       ` James Bottomley
     [not found]       ` <1453567445.2470.24.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-01-23 17:18         ` Andy Shevchenko
2016-01-23 17:18           ` Andy Shevchenko
     [not found]           ` <CAHp75Vdc9=uotvaf4pQfRoViyWuEXhXjZH7GVWEG79AquPVi5A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-01-23 18:03             ` James Bottomley
2016-01-23 18:03               ` James Bottomley
     [not found]               ` <1453572191.2470.52.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-01-25  8:31                 ` Andy Shevchenko
2016-01-25  8:31                   ` Andy Shevchenko
     [not found]                   ` <1453710713.2521.200.camel-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2016-01-25 15:25                     ` James Bottomley
2016-01-25 15:25                       ` James Bottomley
2016-01-23 18:12             ` James Bottomley
2016-01-23 18:12               ` James Bottomley
2016-01-23 20:29               ` One Thousand Gnomes
     [not found]                 ` <20160123202926.460b284f-qBU/x9rampVanCEyBjwyrvXRex20P6io@public.gmane.org>
2016-01-23 20:43                   ` H. Peter Anvin
2016-01-23 20:43                     ` H. Peter Anvin
2016-01-25 18:02         ` Elliott, Robert (Persistent Memory)
2016-01-25 18:02           ` Elliott, Robert (Persistent Memory)
     [not found]           ` <94D0CD8314A33A4D9D801C0FE68B40295BF3B840-W1gbDvblbosSZAcGdq5asR6epYMZPwEe5NbjCUgZEJk@public.gmane.org>
2016-01-25 18:56             ` James Bottomley [this message]
2016-01-25 18:56               ` James Bottomley
     [not found]               ` <1453748172.2363.36.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-01-25 19:28                 ` Andy Shevchenko
2016-01-25 19:28                   ` Andy Shevchenko
     [not found]                   ` <CAHp75VdYRzC9TcDpKxq=xddA0zgVk=5_25uXaimn1tOMZVeK4Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-01-25 19:45                     ` James Bottomley
2016-01-25 19:45                       ` James Bottomley
     [not found]                       ` <1453751131.2363.54.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-01-25 20:01                         ` Andy Shevchenko
2016-01-25 20:01                           ` Andy Shevchenko
     [not found]                           ` <CAHp75VeXHoyOgFSb4vzWBmELH_yJx1mSN+quxue=tSZCh5sTXw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-01-25 20:18                             ` James Bottomley
2016-01-25 20:18                               ` James Bottomley
2016-01-25 20:37                             ` Elliott, Robert (Persistent Memory)
2016-01-25 20:37                               ` Elliott, Robert (Persistent Memory)
2016-01-26 11:50                               ` Matt Fleming
     [not found]                                 ` <20160126115041.GA7478-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
2016-01-26 11:59                                   ` Andy Shevchenko
2016-01-26 11:59                                     ` Andy Shevchenko
     [not found]                                     ` <1453809566.2521.239.camel-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2016-01-28  9:29                                       ` Matt Fleming
2016-01-28  9:29                                         ` Matt Fleming
2016-01-28 11:15                                         ` Andy Shevchenko
2016-01-28 11:15                                           ` Andy Shevchenko
2016-01-25 20:44                             ` James Bottomley
2016-01-25 20:44                               ` James Bottomley
     [not found] ` <1453560913-134672-1-git-send-email-andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2016-01-23 14:55   ` [PATCH v3 4/4] x86/efi: Use proper units in efi_find_mirror() Andy Shevchenko
2016-01-23 14:55     ` Andy Shevchenko
2016-01-23 16:34   ` [PATCH v3 0/4] x86/efi: use binary units when printing James Bottomley
2016-01-23 16:34     ` James Bottomley
     [not found]     ` <1453566877.2470.15.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-01-23 17:20       ` Andy Shevchenko
2016-01-23 17:20         ` Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1453748172.2363.36.camel@HansenPartnership.com \
    --to=james.bottomley-d9phhud1jfjcxq6kfmz53/egyhegw8jk@public.gmane.org \
    --cc=akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org \
    --cc=andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org \
    --cc=elliott-ZPxbGqLxI0U@public.gmane.org \
    --cc=hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org \
    --cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-qQsb+v5E8BnlAoU/VqSP6n9LOBIZ5rWg@public.gmane.org \
    --cc=matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org \
    --cc=mingo-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
    --cc=tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.